diff --git a/.github/workflows/hugo.yaml b/.github/workflows/hugo.yaml new file mode 100644 index 0000000..32966b9 --- /dev/null +++ b/.github/workflows/hugo.yaml @@ -0,0 +1,78 @@ +# Sample workflow for building and deploying a Hugo site to GitHub Pages +name: Deploy Hugo site to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: + - hugo + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +# Default to bash +defaults: + run: + shell: bash + +jobs: + # Build job + build: + runs-on: ubuntu-latest + env: + HUGO_VERSION: 0.128.0 + steps: + - name: Install Hugo CLI + run: | + wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ + && sudo dpkg -i ${{ runner.temp }}/hugo.deb + - name: Install Dart Sass + run: sudo snap install dart-sass + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - name: Setup Pages + id: pages + uses: actions/configure-pages@v5 + - name: Install Node.js dependencies + run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" + - name: Build with Hugo + env: + HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache + HUGO_ENVIRONMENT: production + TZ: America/Los_Angeles + run: | + hugo \ + --gc \ + --minify \ + --baseURL "${{ steps.pages.outputs.base_url }}/" + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./public + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a3c845 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.Rproj.user +.Rhistory +.RData +.Ruserdata +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/R/build.R b/R/build.R new file mode 100644 index 0000000..0227296 --- /dev/null +++ b/R/build.R @@ -0,0 +1,2 @@ +# An optional custom script to run before Hugo builds your site. +# You can delete it if you do not need it. diff --git a/R/build2.R b/R/build2.R new file mode 100644 index 0000000..49a1637 --- /dev/null +++ b/R/build2.R @@ -0,0 +1,2 @@ +# An optional custom script to run after Hugo builds your site. +# You can delete it if you do not need it. diff --git a/R/build_one.R b/R/build_one.R new file mode 100644 index 0000000..49b2064 --- /dev/null +++ b/R/build_one.R @@ -0,0 +1,18 @@ +local({ + # fall back on "/" if baseurl is not specified + baseurl = blogdown:::get_config2("baseurl", default = "/") + knitr::opts_knit$set(base.url = baseurl) + knitr::render_jekyll() # set output hooks + + # input/output filenames as two arguments to Rscript + a = commandArgs(TRUE) + d = gsub("^_|[.][a-zA-Z]+$", "", a[1]) + knitr::opts_chunk$set( + fig.path = sprintf("figure/%s/", d), + cache.path = sprintf("cache/%s/", d) + ) + knitr::knit( + a[1], a[2], quiet = TRUE, encoding = "UTF-8", + envir = globalenv() + ) +}) \ No newline at end of file diff --git a/archetypes/default.md b/archetypes/default.md new file mode 100644 index 0000000..26f317f --- /dev/null +++ b/archetypes/default.md @@ -0,0 +1,5 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- diff --git a/assets/css/dark.css b/assets/css/dark.css new file mode 100644 index 0000000..463a721 --- /dev/null +++ b/assets/css/dark.css @@ -0,0 +1,181 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +blockquote { + border-color: red; + background-color: #FCF5E5; + color: black; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-family: 'Fira Sans', sans-serif; + font-size: 18px; + font-weight: 400; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + border-color: red; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/assets/css/fonts.css b/assets/css/fonts.css new file mode 100644 index 0000000..36d446d --- /dev/null +++ b/assets/css/fonts.css @@ -0,0 +1,45 @@ +/* fira-sans-regular - latin */ +@font-face { + font-display: swap; + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 400; + src: url('../fonts/fira-sans-v10-latin-regular.eot'); /* IE9 Compat Modes */ + src: local('Fira Sans Regular'), local('FiraSans-Regular'), + url('../fonts/fira-sans-v10-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/fira-sans-v10-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/fira-sans-v10-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/fira-sans-v10-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/fira-sans-v10-latin-regular.svg#FiraSans') format('svg'); /* Legacy iOS */ +} +/* roboto-mono-regular - latin */ +@font-face { + font-display: swap; + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + src: url('../fonts/roboto-mono-v12-latin-regular.eot'); /* IE9 Compat Modes */ + src: url('../fonts/roboto-mono-v12-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/roboto-mono-v12-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/roboto-mono-v12-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/roboto-mono-v12-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/roboto-mono-v12-latin-regular.svg#RobotoMono') format('svg'); /* Legacy iOS */ +} +/* ibm-plex-mono-500italic - latin */ +@font-face { + font-display: swap; + font-family: 'IBM Plex Mono'; + font-style: italic; + font-weight: 500; + src: url('../fonts/ibm-plex-mono-v6-latin-500italic.eot'); /* IE9 Compat Modes */ + src: local('IBM Plex Mono Medium Italic'), local('IBMPlexMono-MediumItalic'), + url('../fonts/ibm-plex-mono-v6-latin-500italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.svg#IBMPlexMono') format('svg'); /* Legacy iOS */ +} + +@page { + size: auto; +} diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..5d6d966 --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,341 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Block quote*/ +blockquote { + border-color: red; + background-color: #FCF5E5; + color: black; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-family: 'Fira Sans', sans-serif; + font-size: 18px; + font-weight: 400; +} + + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..6090a78 --- /dev/null +++ b/config.yaml @@ -0,0 +1,79 @@ +baseURL: https://bluevolvo87.github.io/themedianduck +relativeUrls: true +languageCode: en-us +title: The Median Duck +theme: archie +copyright: © Christopher Nam +googleAnalytics: "G-61T5JLRMP0" +pygmentsstyle: monokai +pygmentscodefences: yes +pygmentscodefencesguesssyntax: yes +params: + homePosts: 1 + mode: toggle + social: + - icon: github + name: GitHub + url: https://github.com/bluevolvo87/themedianduck + + - icon: tv + name: YouTube Channel + url: https://youtube.com/naanbread87/ + + - icon: coffee + name: BuyMeACoffee + url: https://buymeacoffee.com/bluevolvo87 + + - icon: music + name: Piano + url: https://www.youtube.com/playlist?list=PL8smthAx7GcfC-gZv6zGNoORClnEXq-ru + + - icon: smile + name: Taskmaster Silliness + url: https://www.youtube.com/playlist?list=PL8smthAx7GcdBfg9C_TRtPC_8m99ho6Ou + + subtitle: vires in notitia + description: "Educating Data Science through Taskmaster" + useCDN: no + + highlightjsVersion: "9.12.0" + highlightjsCDN: "//cdnjs.cloudflare.com/ajax/libs" + highlightjsLang: ["r", "yaml"] + highlightjsTheme: "github" + logo: "/img/logo.jpg" +menu: + main: + - name: Home + url: / + weight: 1 + - name: The Vision + url: /vision + weight: 2 + - name: Posts + url: /posts + weight: 3 + - name: Tasks + url: /tasks + weight: 4 + - name: About Me + url: /about + weight: 5 + - name: Resources + url: /resources + weight: 6 + +outputs: +home: [html, rss, json] +permalinks: + posts: "/:year/:month/:slug/" +taxonomies: + category: categories + series: series + tag: tags + section: sections + +markup: + tableOfContents: + startLevel: 1 + endLevel: 2 + diff --git a/content/_index.Rmd b/content/_index.Rmd new file mode 100644 index 0000000..e9bfd33 --- /dev/null +++ b/content/_index.Rmd @@ -0,0 +1,23 @@ +--- +title: The Median Duck Home Page +author: Christopher Nam +editor_options: + markdown: + wrap: 72 +--- + +# Welcome! + +![](img/duck_tt.png) + +Welcome to The Median Duck, a self initiated project that aims to +educate and entertain the general public on data analytic topics through +the hit UK TV show [Taskmaster](https://en.wikipedia.org/wiki/Taskmaster_(TV_series)). + +This project is in its early stages, but great things are planned; see +this [vision document](vision) for the ambitious plans that I have in mind. + +> **Your Time Starts Now!** + +------------------------------------------------------------------------ + diff --git a/content/_index.html b/content/_index.html new file mode 100644 index 0000000..ea285dc --- /dev/null +++ b/content/_index.html @@ -0,0 +1,23 @@ +--- +title: The Median Duck Home Page +author: Christopher Nam +editor_options: + markdown: + wrap: 72 +--- + + + +
+

Welcome!

+

+

Welcome to The Median Duck, a self initiated project that aims to +educate and entertain the general public on data analytic topics through +the hit UK TV show Taskmaster.

+

This project is in its early stages, but great things are planned; see +this vision document for the ambitious plans that I have in mind.

+
+

Your Time Starts Now!

+
+
+
diff --git a/content/about.md b/content/about.md new file mode 100644 index 0000000..8483433 --- /dev/null +++ b/content/about.md @@ -0,0 +1,52 @@ +--- +aliases: +- "about-me" +author: Christopher Nam +date: "2024-07-08" +description: About Me +title: About Me +--- + +# My Professional Background + +I obtained a PhD in Statistics from the University of Warwick in 2013, my thesis title was *"Uncertainty in Changepoints in Time Series"* [^1]. I'm delighted that Dr Little Alex Horne recently became associated with my alma mater through the [Taskmaster Education](https://taskmastereducation.com/news/dr-little-alex-horne) scheme. + +[^1]: I'm sure you eager readers can find my thesis online and be gently amused by my chapter quotes. + +I have 10 years of industry experience as a Research Scientist/Data Scientist at Amazon and Samsung, predominantly demand forecasting at scale for products. From this experience, I have some experience on running projects at scale, with rigor (automation, repeatability) and compromises that need to be made (whether it be technical, monetary, mental). + +# My Personal Motivation + +There are a variety of personal reasons why I am starting *The Median Duck*. + +Perhaps optimistically, I want to (stealthy) educate others of analytics to the general public in a fun and amusing manner. Statistics is not taught particularly well in the UK, often seen as a boring number crunching and often a medium to lie. Add to this, I want to instill best practices and the graft work that I have experienced over my years, and that are often overlooked in courses and textbooks (importance of good quality data, automated workflows, etc.). + +I made the somewhat brave decision to become self employed at the start of 2024, and have various ventures in the work to provide some income and keep me entertained on a daily basis (piano teaching, piano performance, admin for my housing association). The Median Duck is one of these ventures. + +I don't expect this venture to be a money maker (major or minor), but I do want to retain my engagement in the data science and statistics field. Add to this, my "imposter syndrome" often wants me to relearn the basics. + +I do have some aspirations to potentially go into data journalism through data science and analytics and this venture may provide some experience and build up a portfolio of work. + +Finally, I do not claim to be a full expert and entirely knowledgeable about the analysis I will be covering[^2]. However I'm always eager to learn new topics and also educate others; I believe I am an educator and teacher at my core. My passion for Taskmaster and prior experience with the analytics field thus makes *The Median Duck* this the ideal vehicle. + +[^2]: This is the [Imposter Syndrome](https://www.webmd.com/balance/what-is-imposter-syndrome) talking for the most part... + +# My Taskmaster Journey + +My Taskmaster journey properly started during 2020 (and the global pandemic), when the Series 2 task "order something without using certain words" was recommended to me on YouTube. Once I watched this task, I was hooked and consequently went down the Taskmaster rabbit hole and binged whatever series were available. + +However, prior to this, I was initially quite dismissive of Taskmaster. I had previously associated "Taskmaster" with "Ticketmaster" and thus erroneously thought it was going to be a dull show in which extortionate ticket scalping would occur. How wrong I was... + +Since 2020, I have watched each series of Taskmaster (mainly UK) near the time of broadcast, and consumed Taskmaster adjacent material (the podcast, comedians appearances on other comedy shows etc.). + +I have also unofficially (and jokingly) assigned myself the title of *"Taskmaster Representative of the Pacific Northwest"* as I have referred numerous friends and colleagues about Taskmaster and also informed them of when the next series is broadcasting. + +# These are a Few of My Favourite Taskmaster Things... + +- **Favourite Task:** Ringtone Choreography (S4E4) +- **Favourite Series:** Series 4 or 5. +- **Favourite Contestant:** Victoria Coren Mitchell[^3] +- **Favourite Quote(s):** "Friendship is Truth" +- **Degrees of Separation to Alex Horne (to my knowledge):** 3 + +[^3]: Fun fact: I actively squealed when VCM was announced. She's a fascinating person with extremely varied career (to name a few: author, broadcaster/presenter, professional player, pornographer, former stand up comedian, customised inhaler trendsetter...) diff --git a/content/archives.md b/content/archives.md new file mode 100644 index 0000000..a0271c3 --- /dev/null +++ b/content/archives.md @@ -0,0 +1,5 @@ +--- +date: "2019-05-28" +layout: archives +type: section +--- diff --git a/content/homepage/about.md b/content/homepage/about.md new file mode 100644 index 0000000..c9aa233 --- /dev/null +++ b/content/homepage/about.md @@ -0,0 +1,11 @@ +--- +title: 'Our Difference' +button: 'About us' +weight: 2 +--- + +I don't think this has any affect? + + +Lorem ipsum dolor sit amet, et essent mediocritatem quo, choro volumus oporteat an mei. ipsum dolor sit amet, et essent mediocritatem quo, + diff --git a/content/homepage/index.md b/content/homepage/index.md new file mode 100644 index 0000000..1723d81 --- /dev/null +++ b/content/homepage/index.md @@ -0,0 +1,5 @@ +--- +headless : true +--- + +Really? Is this not the hompage editor? \ No newline at end of file diff --git a/content/homepage/work.md b/content/homepage/work.md new file mode 100644 index 0000000..b8005f3 --- /dev/null +++ b/content/homepage/work.md @@ -0,0 +1,10 @@ +--- +title: 'We Help Business Grow' +button: 'Our Work' +weight: 1 +--- + +Similarly, I don't think this has any impact. + + +Lorem ipsum dolor sit amet, et essent mediocritatem quo, choro volumus oporteat an mei. Numquam dolores mel eu, mea docendi omittantur et, mea ea duis erat. Elit melius cu ius. Per ex novum tantas putant, ei his nullam aliquam apeirian. Aeterno quaestio constituto sea an, no eum intellegat assueverit. \ No newline at end of file diff --git a/content/index.html b/content/index.html new file mode 100644 index 0000000..4969859 --- /dev/null +++ b/content/index.html @@ -0,0 +1,15 @@ +--- +title: Home Page Beta +author: Christopher Nam +menu: + header: + weight: 1 +--- + + + +

Is this the homepage? +I hope so….

+

So I can see this information in the description part. +How do I get it to appear in the main body of the page.

+

If you see this, then you’ve cracked the problem! Try.

diff --git a/content/posts/2020-12-01-r-rmarkdown/index.Rmd b/content/posts/2020-12-01-r-rmarkdown/index.Rmd new file mode 100644 index 0000000..8768d78 --- /dev/null +++ b/content/posts/2020-12-01-r-rmarkdown/index.Rmd @@ -0,0 +1,38 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(collapse = TRUE) +``` + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + +```{r cars} +summary(cars) +fit <- lm(dist ~ speed, data = cars) +fit +``` + +# Including Plots + +You can also embed plots. See Figure \@ref(fig:pie) for example: + +```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE} +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` diff --git a/content/posts/2020-12-01-r-rmarkdown/index.html b/content/posts/2020-12-01-r-rmarkdown/index.html new file mode 100644 index 0000000..14c4e47 --- /dev/null +++ b/content/posts/2020-12-01-r-rmarkdown/index.html @@ -0,0 +1,50 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + + + +
+

R Markdown

+

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

+

You can embed an R code chunk like this:

+
summary(cars)
+##      speed           dist       
+##  Min.   : 4.0   Min.   :  2.00  
+##  1st Qu.:12.0   1st Qu.: 26.00  
+##  Median :15.0   Median : 36.00  
+##  Mean   :15.4   Mean   : 42.98  
+##  3rd Qu.:19.0   3rd Qu.: 56.00  
+##  Max.   :25.0   Max.   :120.00
+fit <- lm(dist ~ speed, data = cars)
+fit
+## 
+## Call:
+## lm(formula = dist ~ speed, data = cars)
+## 
+## Coefficients:
+## (Intercept)        speed  
+##     -17.579        3.932
+
+
+

Including Plots

+

You can also embed plots. See Figure 1 for example:

+
par(mar = c(0, 1, 0, 1))
+pie(
+  c(280, 60, 20),
+  c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
+  col = c('#0292D8', '#F7EA39', '#C4B632'),
+  init.angle = -50, border = NA
+)
+
+A fancy pie chart. +

+Figure 1: A fancy pie chart. +

+
+
diff --git a/content/posts/2020-12-01-r-rmarkdown/index.md b/content/posts/2020-12-01-r-rmarkdown/index.md new file mode 100644 index 0000000..405875c --- /dev/null +++ b/content/posts/2020-12-01-r-rmarkdown/index.md @@ -0,0 +1,57 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + + + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + + +```r +summary(cars) +## speed dist +## Min. : 4.0 Min. : 2.00 +## 1st Qu.:12.0 1st Qu.: 26.00 +## Median :15.0 Median : 36.00 +## Mean :15.4 Mean : 42.98 +## 3rd Qu.:19.0 3rd Qu.: 56.00 +## Max. :25.0 Max. :120.00 +fit <- lm(dist ~ speed, data = cars) +fit +## +## Call: +## lm(formula = dist ~ speed, data = cars) +## +## Coefficients: +## (Intercept) speed +## -17.579 3.932 +``` + +# Including Plots + +You can also embed plots. See Figure 1 for example: + + +```r +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` + +
+A fancy pie chart. +

Figure 1: A fancy pie chart.

+
diff --git a/content/posts/2020-12-01-r-rmarkdown/index_files/figure-html/pie-1.png b/content/posts/2020-12-01-r-rmarkdown/index_files/figure-html/pie-1.png new file mode 100644 index 0000000..eef072f Binary files /dev/null and b/content/posts/2020-12-01-r-rmarkdown/index_files/figure-html/pie-1.png differ diff --git a/content/posts/2024-07-06-new-post-on-archie/index.Rmarkdown b/content/posts/2024-07-06-new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..e9196ed --- /dev/null +++ b/content/posts/2024-07-06-new-post-on-archie/index.Rmarkdown @@ -0,0 +1,25 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? \ No newline at end of file diff --git a/content/posts/2024-07-06-new-post-on-archie/index.markdown b/content/posts/2024-07-06-new-post-on-archie/index.markdown new file mode 100644 index 0000000..3b98a5e --- /dev/null +++ b/content/posts/2024-07-06-new-post-on-archie/index.markdown @@ -0,0 +1,30 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + + +```r +rnorm(5) +``` + +``` +## [1] -0.3637057 -0.4214060 0.6501004 -0.8329920 1.3021409 +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..53dfb90 --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,162 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +section: + - intro + - setup + - data +series: "Strength in Data" +tags: ["Strength in Data", "Beginner"] +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 2 + number_sections: true + df_print: "default" +--- + +```{r setup, include=FALSE, echo = FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../", + tidy = TRUE + ) +options(width = 1000) +``` + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +This article provides an overview of *Trabajo de las Mesas*, a pivotal database that will be central to this project. + +The article will also provide guidance on how to connect to the database from within `R`. + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM [^1]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +[^1]: Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture. + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +For some musings on TdlM, data quality and assumptions made, see this [post](/2024/07/data-quality-musings/). + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead intuitively to repeatable and reproduceable analysis. Connecting to the database from a (statistical) programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I am opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download, message = FALSE} +library(here) #library to help with identifying the repo working directory + +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +db_file_name <- "taskmaster.db" +data_dir <- here("static", "data") + +db_data_location <- file.path(data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(data_dir))){ + dir.create(file.path(data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` + +## Connecting to the `.db` file + +Now that the database file has been downloaded successfully, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +# Install packages if does not exist, then load. +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + +## Querying the Database +With the database connection established, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation is also possible. + +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +-- Days between air start date, and last studio record date +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts -- Series information +LEFT JOIN people tp -- People/Contestant information + ON ts.id = tp.series + AND ts.champion = tp.id +WHERE ts.special <> 1 -- Consider regular series +" + +results <- dbGetQuery(tm_db, query) + +results +``` + +```{r longest_lag, include = FALSE} +longest_lag_df <- results[which.max(results$broadcast_lag_days),] +``` + +# A recording to airing insight... +The results of this query already indicate interesting insights; `r longest_lag_df$name` has the largest known delay between studio recording and airing of `r longest_lag_df$broadcast_lag_days` days (approximately `r round(longest_lag_df$broadcast_lag_days/7)` weeks). This is a noticeable deviation from prior series. Future series also seem delayed, although to a lesser extent. + +**Potential followup questions:** +- Could the 2020 pandemic have initiated this lag? +- Were there other production changes that led to this lag? + +# Times Up! +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.markdown b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.markdown new file mode 100644 index 0000000..038ef8d --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.markdown @@ -0,0 +1,200 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +section: + - intro + - setup + - data +series: "Strength in Data" +tags: ["Strength in Data", "Beginner"] +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 2 + number_sections: true + df_print: "default" +--- + + + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +This article provides an overview of *Trabajo de las Mesas*, a pivotal database that will be central to this project. + +The article will also provide guidance on how to connect to the database from within `R`. + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM [^1]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +[^1]: Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture. + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +For some musings on TdlM, data quality and assumptions made, see this [post](/2024/07/data-quality-musings/). + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead intuitively to repeatable and reproduceable analysis. Connecting to the database from a (statistical) programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I am opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + + +```r +library(here) #library to help with identifying the repo working directory + +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +db_file_name <- "taskmaster.db" +data_dir <- here("static", "data") + +db_data_location <- file.path(data_dir, db_file_name) + + +# Create Data Directory if does not exist +if (!file.exists(file.path(data_dir))) { + dir.create(file.path(data_dir)) +} + +# Download file specified by URL, save in the local destination. +if (!file.exists(db_data_location)) { + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} +``` + +## Connecting to the `.db` file + +Now that the database file has been downloaded successfully, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + + +```r +package_name <- "RSQLite" + +# Install packages if does not exist, then load. +if (!require(package_name, character.only = TRUE)) { + install.packages(package_name, character.only = TRUE) +} else { + library(package_name, character.only = TRUE) +} +``` + +``` +## Loading required package: RSQLite +``` + +```r +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) +``` + +If successful, we should be able to list all the tables included in the database. + + +```r +# List all tables that are available in the database +dbListTables(tm_db) +``` + +``` +## [1] "attempts" "discrepancies" "episode_scores" "episodes" "intros" "measurements" "normalized_scores" "objectives" "people" "podcast" "profanity" "series" "series_scores" "special_locations" "task_briefs" "task_readers" "task_winners" "tasks" "tasks_by_objective" "team_tasks" "teams" "title_coiners" "title_stats" +``` + +## Querying the Database +With the database connection established, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + + +```r +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +``` +## id name episodes champion air_start air_end studio_start studio_end points tasks special TMI +## 1 -7 CoC III 0 NA 2024-??-?? 2024-??-?? 2023-11-28 2023-11-28 NA NA 1 88 +## 2 -6 NYT 2024 0 NA 2024-01-01 2024-01-01 2023-11-27 2023-11-27 NA NA 1 87 +## 3 -5 NYT 2023 1 96 2023-01-01 2023-01-01 2022-11-22 2022-11-22 76 5 1 66 +## 4 -4 CoC II 1 87 2022-06-23 2022-06-23 2021-09-15 2021-09-15 66 5 1 46 +## 5 -3 NYT 2022 1 73 2022-01-01 2022-01-01 68 5 1 47 +## 6 -2 NYT 2021 1 62 2021-01-01 2021-01-01 62 5 1 12 +## 7 -1 CoC 2 29 2017-12-13 2017-12-20 2017-11-20 2017-11-20 164 10 1 6 +## 8 1 Series 1 6 4 2015-07-28 2015-09-01 2015-03-23 2015-03-25 436 32 0 1 +## 9 2 Series 2 5 11 2016-06-21 2016-07-19 417 28 0 2 +## 10 3 Series 3 5 16 2016-10-04 2016-11-01 386 27 0 3 +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation is also possible. + + +```r +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +-- Days between air start date, and last studio record date +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts -- Series information +LEFT JOIN people tp -- People/Contestant information + ON ts.id = tp.series + AND ts.champion = tp.id +WHERE ts.special <> 1 -- Consider regular series +" + +results <- dbGetQuery(tm_db, query) + +results +``` + +``` +## name special_flag champion_name chamption_seat studio_end air_start broadcast_lag_days +## 1 Series 1 0 Josh Widdicombe 2 2015-03-25 2015-07-28 125 +## 2 Series 2 0 Katherine Ryan 4 2016-06-21 NA +## 3 Series 3 0 Rob Beckett 4 2016-10-04 NA +## 4 Series 4 0 Noel Fielding 5 2017-04-25 NA +## 5 Series 5 0 Bob Mortimer 2 2017-07-06 2017-09-13 69 +## 6 Series 6 0 Liza Tarbuck 3 2018-03-28 2018-05-02 35 +## 7 Series 7 0 Kerry Godliman 3 2018-07-25 2018-09-05 42 +## 8 Series 8 0 Lou Sanders 3 2019-03-27 2019-05-08 42 +## 9 Series 9 0 Ed Gamble 2 2019-07-24 2019-09-04 42 +## 10 Series 10 0 Richard Herring 5 2020-07-29 2020-10-15 78 +## 11 Series 11 0 Sarah Kendall 5 2021-03-18 NA +## 12 Series 12 0 Morgana Robinson 4 2021-09-23 NA +## 13 Series 13 0 Sophie Duker 5 2021-09-22 2022-04-14 204 +## 14 Series 14 0 Dara Ó Briain 1 2022-05-05 2022-09-29 147 +## 15 Series 15 0 Mae Martin 5 2022-09-28 2023-03-30 183 +## 16 Series 16 0 Sam Campbell 3 2023-05-12 2023-09-21 132 +``` + + + +# A recording to airing insight... +The results of this query already indicate interesting insights; Series 13 has the largest known delay between studio recording and airing of 204 days (approximately 29 weeks). This is a noticeable deviation from prior series. Future series also seem delayed, although to a lesser extent. + +**Potential followup questions:** +- Could the 2020 pandemic have initiated this lag? +- Were there other production changes that led to this lag? + +# Times Up! +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/css/crosstalk.min.css b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/css/crosstalk.min.css new file mode 100644 index 0000000..6b45382 --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/css/crosstalk.min.css @@ -0,0 +1 @@ +.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js new file mode 100644 index 0000000..fd9eb53 --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js @@ -0,0 +1,1474 @@ +(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b) { + return 1; + } +} + +/** + * @private + */ + +var FilterSet = function () { + function FilterSet() { + _classCallCheck(this, FilterSet); + + this.reset(); + } + + _createClass(FilterSet, [{ + key: "reset", + value: function reset() { + // Key: handle ID, Value: array of selected keys, or null + this._handles = {}; + // Key: key string, Value: count of handles that include it + this._keys = {}; + this._value = null; + this._activeHandles = 0; + } + }, { + key: "update", + value: function update(handleId, keys) { + if (keys !== null) { + keys = keys.slice(0); // clone before sorting + keys.sort(naturalComparator); + } + + var _diffSortedLists = (0, _util.diffSortedLists)(this._handles[handleId], keys), + added = _diffSortedLists.added, + removed = _diffSortedLists.removed; + + this._handles[handleId] = keys; + + for (var i = 0; i < added.length; i++) { + this._keys[added[i]] = (this._keys[added[i]] || 0) + 1; + } + for (var _i = 0; _i < removed.length; _i++) { + this._keys[removed[_i]]--; + } + + this._updateValue(keys); + } + + /** + * @param {string[]} keys Sorted array of strings that indicate + * a superset of possible keys. + * @private + */ + + }, { + key: "_updateValue", + value: function _updateValue() { + var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._allKeys; + + var handleCount = Object.keys(this._handles).length; + if (handleCount === 0) { + this._value = null; + } else { + this._value = []; + for (var i = 0; i < keys.length; i++) { + var count = this._keys[keys[i]]; + if (count === handleCount) { + this._value.push(keys[i]); + } + } + } + } + }, { + key: "clear", + value: function clear(handleId) { + if (typeof this._handles[handleId] === "undefined") { + return; + } + + var keys = this._handles[handleId]; + if (!keys) { + keys = []; + } + + for (var i = 0; i < keys.length; i++) { + this._keys[keys[i]]--; + } + delete this._handles[handleId]; + + this._updateValue(); + } + }, { + key: "value", + get: function get() { + return this._value; + } + }, { + key: "_allKeys", + get: function get() { + var allKeys = Object.keys(this._keys); + allKeys.sort(naturalComparator); + return allKeys; + } + }]); + + return FilterSet; +}(); + +exports.default = FilterSet; + +},{"./util":11}],4:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.default = group; + +var _var2 = require("./var"); + +var _var3 = _interopRequireDefault(_var2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// Use a global so that multiple copies of crosstalk.js can be loaded and still +// have groups behave as singletons across all copies. +global.__crosstalk_groups = global.__crosstalk_groups || {}; +var groups = global.__crosstalk_groups; + +function group(groupName) { + if (groupName && typeof groupName === "string") { + if (!groups.hasOwnProperty(groupName)) { + groups[groupName] = new Group(groupName); + } + return groups[groupName]; + } else if ((typeof groupName === "undefined" ? "undefined" : _typeof(groupName)) === "object" && groupName._vars && groupName.var) { + // Appears to already be a group object + return groupName; + } else if (Array.isArray(groupName) && groupName.length == 1 && typeof groupName[0] === "string") { + return group(groupName[0]); + } else { + throw new Error("Invalid groupName argument"); + } +} + +var Group = function () { + function Group(name) { + _classCallCheck(this, Group); + + this.name = name; + this._vars = {}; + } + + _createClass(Group, [{ + key: "var", + value: function _var(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + if (!this._vars.hasOwnProperty(name)) this._vars[name] = new _var3.default(this, name); + return this._vars[name]; + } + }, { + key: "has", + value: function has(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + return this._vars.hasOwnProperty(name); + } + }]); + + return Group; +}(); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./var":12}],5:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _selection = require("./selection"); + +var _filter = require("./filter"); + +var _input = require("./input"); + +require("./input_selectize"); + +require("./input_checkboxgroup"); + +require("./input_slider"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var defaultGroup = (0, _group2.default)("default"); + +function var_(name) { + return defaultGroup.var(name); +} + +function has(name) { + return defaultGroup.has(name); +} + +if (global.Shiny) { + global.Shiny.addCustomMessageHandler("update-client-value", function (message) { + if (typeof message.group === "string") { + (0, _group2.default)(message.group).var(message.name).set(message.value); + } else { + var_(message.name).set(message.value); + } + }); +} + +var crosstalk = { + group: _group2.default, + var: var_, + has: has, + SelectionHandle: _selection.SelectionHandle, + FilterHandle: _filter.FilterHandle, + bind: _input.bind +}; + +/** + * @namespace crosstalk + */ +exports.default = crosstalk; + +global.crosstalk = crosstalk; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./group":4,"./input":6,"./input_checkboxgroup":7,"./input_selectize":8,"./input_slider":9,"./selection":10}],6:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.register = register; +exports.bind = bind; +var $ = global.jQuery; + +var bindings = {}; + +function register(reg) { + bindings[reg.className] = reg; + if (global.document && global.document.readyState !== "complete") { + $(function () { + bind(); + }); + } else if (global.document) { + setTimeout(bind, 100); + } +} + +function bind() { + Object.keys(bindings).forEach(function (className) { + var binding = bindings[className]; + $("." + binding.className).not(".crosstalk-input-bound").each(function (i, el) { + bindInstance(binding, el); + }); + }); +} + +// Escape jQuery identifier +function $escape(val) { + return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1"); +} + +function bindEl(el) { + var $el = $(el); + Object.keys(bindings).forEach(function (className) { + if ($el.hasClass(className) && !$el.hasClass("crosstalk-input-bound")) { + var binding = bindings[className]; + bindInstance(binding, el); + } + }); +} + +function bindInstance(binding, el) { + var jsonEl = $(el).find("script[type='application/json'][data-for='" + $escape(el.id) + "']"); + var data = JSON.parse(jsonEl[0].innerText); + + var instance = binding.factory(el, data); + $(el).data("crosstalk-instance", instance); + $(el).addClass("crosstalk-input-bound"); +} + +if (global.Shiny) { + var inputBinding = new global.Shiny.InputBinding(); + var _$ = global.jQuery; + _$.extend(inputBinding, { + find: function find(scope) { + return _$(scope).find(".crosstalk-input"); + }, + initialize: function initialize(el) { + if (!_$(el).hasClass("crosstalk-input-bound")) { + bindEl(el); + } + }, + getId: function getId(el) { + return el.id; + }, + getValue: function getValue(el) {}, + setValue: function setValue(el, value) {}, + receiveMessage: function receiveMessage(el, data) {}, + subscribe: function subscribe(el, callback) { + _$(el).data("crosstalk-instance").resume(); + }, + unsubscribe: function unsubscribe(el) { + _$(el).data("crosstalk-instance").suspend(); + } + }); + global.Shiny.inputBindings.register(inputBinding, "crosstalk.inputBinding"); +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{}],7:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-checkboxgroup", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + var $el = $(el); + $el.on("change", "input[type='checkbox']", function () { + var checked = $el.find("input[type='checkbox']:checked"); + if (checked.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + checked.each(function () { + data.map[this.value].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],8:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-select", + + factory: function factory(el, data) { + /* + * items: {value: [...], label: [...]} + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + + var first = [{ value: "", label: "(All)" }]; + var items = util.dataframeToD3(data.items); + var opts = { + options: first.concat(items), + valueField: "value", + labelField: "label", + searchField: "label" + }; + + var select = $(el).find("select")[0]; + + var selectize = $(select).selectize(opts)[0].selectize; + + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + selectize.on("change", function () { + if (selectize.items.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + selectize.items.forEach(function (group) { + data.map[group].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6,"./util":11}],9:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; +var strftime = global.strftime; + +input.register({ + className: "crosstalk-input-slider", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var opts = {}; + var $el = $(el).find("input"); + var dataType = $el.data("data-type"); + var timeFormat = $el.data("time-format"); + var round = $el.data("round"); + var timeFormatter = void 0; + + // Set up formatting functions + if (dataType === "date") { + timeFormatter = strftime.utc(); + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "datetime") { + var timezone = $el.data("timezone"); + if (timezone) timeFormatter = strftime.timezone(timezone);else timeFormatter = strftime; + + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "number") { + if (typeof round !== "undefined") opts.prettify = function (num) { + var factor = Math.pow(10, round); + return Math.round(num * factor) / factor; + }; + } + + $el.ionRangeSlider(opts); + + function getValue() { + var result = $el.data("ionRangeSlider").result; + + // Function for converting numeric value from slider to appropriate type. + var convert = void 0; + var dataType = $el.data("data-type"); + if (dataType === "date") { + convert = function convert(val) { + return formatDateUTC(new Date(+val)); + }; + } else if (dataType === "datetime") { + convert = function convert(val) { + // Convert ms to s + return +val / 1000; + }; + } else { + convert = function convert(val) { + return +val; + }; + } + + if ($el.data("ionRangeSlider").options.type === "double") { + return [convert(result.from), convert(result.to)]; + } else { + return convert(result.from); + } + } + + var lastKnownKeys = null; + + $el.on("change.crosstalkSliderInput", function (event) { + if (!$el.data("updating") && !$el.data("animating")) { + var _getValue = getValue(), + _getValue2 = _slicedToArray(_getValue, 2), + from = _getValue2[0], + to = _getValue2[1]; + + var keys = []; + for (var i = 0; i < data.values.length; i++) { + var val = data.values[i]; + if (val >= from && val <= to) { + keys.push(data.keys[i]); + } + } + keys.sort(); + ctHandle.set(keys); + lastKnownKeys = keys; + } + }); + + // let $el = $(el); + // $el.on("change", "input[type="checkbox"]", function() { + // let checked = $el.find("input[type="checkbox"]:checked"); + // if (checked.length === 0) { + // ctHandle.clear(); + // } else { + // let keys = {}; + // checked.each(function() { + // data.map[this.value].forEach(function(key) { + // keys[key] = true; + // }); + // }); + // let keyArray = Object.keys(keys); + // keyArray.sort(); + // ctHandle.set(keyArray); + // } + // }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +// Convert a number to a string with leading zeros +function padZeros(n, digits) { + var str = n.toString(); + while (str.length < digits) { + str = "0" + str; + }return str; +} + +// Given a Date object, return a string in yyyy-mm-dd format, using the +// UTC date. This may be a day off from the date in the local time zone. +function formatDateUTC(date) { + if (date instanceof Date) { + return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2); + } else { + return null; + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],10:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SelectionHandle = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Use this class to read and write (and listen for changes to) the selection + * for a Crosstalk group. This is intended to be used for linked brushing. + * + * If two (or more) `SelectionHandle` instances in the same webpage share the + * same group name, they will share the same state. Setting the selection using + * one `SelectionHandle` instance will result in the `value` property instantly + * changing across the others, and `"change"` event listeners on all instances + * (including the one that initiated the sending) will fire. + * + * @param {string} [group] - The name of the Crosstalk group, or if none, + * null or undefined (or any other falsy value). This can be changed later + * via the [SelectionHandle#setGroup](#setGroup) method. + * @param {Object} [extraInfo] - An object whose properties will be copied to + * the event object whenever an event is emitted. + */ +var SelectionHandle = exports.SelectionHandle = function () { + function SelectionHandle() { + var group = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var extraInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, SelectionHandle); + + this._eventRelay = new _events2.default(); + this._emitter = new util.SubscriptionTracker(this._eventRelay); + + // Name of the group we're currently tracking, if any. Can change over time. + this._group = null; + // The Var we're currently tracking, if any. Can change over time. + this._var = null; + // The event handler subscription we currently have on var.on("change"). + this._varOnChangeSub = null; + + this._extraInfo = util.extend({ sender: this }, extraInfo); + + this.setGroup(group); + } + + /** + * Changes the Crosstalk group membership of this SelectionHandle. The group + * being switched away from (if any) will not have its selection value + * modified as a result of calling `setGroup`, even if this handle was the + * most recent handle to set the selection of the group. + * + * The group being switched to (if any) will also not have its selection value + * modified as a result of calling `setGroup`. If you want to set the + * selection value of the new group, call `set` explicitly. + * + * @param {string} group - The name of the Crosstalk group, or null (or + * undefined) to clear the group. + */ + + + _createClass(SelectionHandle, [{ + key: "setGroup", + value: function setGroup(group) { + var _this = this; + + // If group is unchanged, do nothing + if (this._group === group) return; + // Treat null, undefined, and other falsy values the same + if (!this._group && !group) return; + + if (this._var) { + this._var.off("change", this._varOnChangeSub); + this._var = null; + this._varOnChangeSub = null; + } + + this._group = group; + + if (group) { + this._var = (0, _group2.default)(group).var("selection"); + var sub = this._var.on("change", function (e) { + _this._eventRelay.trigger("change", e, _this); + }); + this._varOnChangeSub = sub; + } + } + + /** + * Retrieves the current selection for the group represented by this + * `SelectionHandle`. + * + * - If no selection is active, then this value will be falsy. + * - If a selection is active, but no data points are selected, then this + * value will be an empty array. + * - If a selection is active, and data points are selected, then the keys + * of the selected data points will be present in the array. + */ + + }, { + key: "_mergeExtraInfo", + + + /** + * Combines the given `extraInfo` (if any) with the handle's default + * `_extraInfo` (if any). + * @private + */ + value: function _mergeExtraInfo(extraInfo) { + // Important incidental effect: shallow clone is returned + return util.extend({}, this._extraInfo ? this._extraInfo : null, extraInfo ? extraInfo : null); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see + * {@link SelectionHandle#value}). + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any options that were + * passed into the `SelectionHandle` constructor). + */ + + }, { + key: "set", + value: function set(selectedKeys, extraInfo) { + if (this._var) this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo)); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any that were passed + * into the `SelectionHandle` constructor). + */ + + }, { + key: "clear", + value: function clear(extraInfo) { + if (this._var) this.set(void 0, this._mergeExtraInfo(extraInfo)); + } + + /** + * Subscribes to events on this `SelectionHandle`. + * + * @param {string} eventType - Indicates the type of events to listen to. + * Currently, only `"change"` is supported. + * @param {SelectionHandle~listener} listener - The callback function that + * will be invoked when the event occurs. + * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel + * this subscription. + */ + + }, { + key: "on", + value: function on(eventType, listener) { + return this._emitter.on(eventType, listener); + } + + /** + * Cancels event subscriptions created by {@link SelectionHandle#on}. + * + * @param {string} eventType - The type of event to unsubscribe. + * @param {string|SelectionHandle~listener} listener - Either the callback + * function previously passed into {@link SelectionHandle#on}, or the + * string that was returned from {@link SelectionHandle#on}. + */ + + }, { + key: "off", + value: function off(eventType, listener) { + return this._emitter.off(eventType, listener); + } + + /** + * Shuts down the `SelectionHandle` object. + * + * Removes all event listeners that were added through this handle. + */ + + }, { + key: "close", + value: function close() { + this._emitter.removeAllListeners(); + this.setGroup(null); + } + }, { + key: "value", + get: function get() { + return this._var ? this._var.get() : null; + } + }]); + + return SelectionHandle; +}(); + +/** + * @callback SelectionHandle~listener + * @param {Object} event - An object containing details of the event. For + * `"change"` events, this includes the properties `value` (the new + * value of the selection, or `undefined` if no selection is active), + * `oldValue` (the previous value of the selection), and `sender` (the + * `SelectionHandle` instance that made the change). + */ + +/** + * @event SelectionHandle#change + * @type {object} + * @property {object} value - The new value of the selection, or `undefined` + * if no selection is active. + * @property {object} oldValue - The previous value of the selection. + * @property {SelectionHandle} sender - The `SelectionHandle` instance that + * changed the value. + */ + +},{"./events":1,"./group":4,"./util":11}],11:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extend = extend; +exports.checkSorted = checkSorted; +exports.diffSortedLists = diffSortedLists; +exports.dataframeToD3 = dataframeToD3; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function extend(target) { + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + for (var i = 0; i < sources.length; i++) { + var src = sources[i]; + if (typeof src === "undefined" || src === null) continue; + + for (var key in src) { + if (src.hasOwnProperty(key)) { + target[key] = src[key]; + } + } + } + return target; +} + +function checkSorted(list) { + for (var i = 1; i < list.length; i++) { + if (list[i] <= list[i - 1]) { + throw new Error("List is not sorted or contains duplicate"); + } + } +} + +function diffSortedLists(a, b) { + var i_a = 0; + var i_b = 0; + + if (!a) a = []; + if (!b) b = []; + + var a_only = []; + var b_only = []; + + checkSorted(a); + checkSorted(b); + + while (i_a < a.length && i_b < b.length) { + if (a[i_a] === b[i_b]) { + i_a++; + i_b++; + } else if (a[i_a] < b[i_b]) { + a_only.push(a[i_a++]); + } else { + b_only.push(b[i_b++]); + } + } + + if (i_a < a.length) a_only = a_only.concat(a.slice(i_a)); + if (i_b < b.length) b_only = b_only.concat(b.slice(i_b)); + return { + removed: a_only, + added: b_only + }; +} + +// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... } +// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ] +function dataframeToD3(df) { + var names = []; + var length = void 0; + for (var name in df) { + if (df.hasOwnProperty(name)) names.push(name); + if (_typeof(df[name]) !== "object" || typeof df[name].length === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof length !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item = void 0; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; +} + +/** + * Keeps track of all event listener additions/removals and lets all active + * listeners be removed with a single operation. + * + * @private + */ + +var SubscriptionTracker = exports.SubscriptionTracker = function () { + function SubscriptionTracker(emitter) { + _classCallCheck(this, SubscriptionTracker); + + this._emitter = emitter; + this._subs = {}; + } + + _createClass(SubscriptionTracker, [{ + key: "on", + value: function on(eventType, listener) { + var sub = this._emitter.on(eventType, listener); + this._subs[sub] = eventType; + return sub; + } + }, { + key: "off", + value: function off(eventType, listener) { + var sub = this._emitter.off(eventType, listener); + if (sub) { + delete this._subs[sub]; + } + return sub; + } + }, { + key: "removeAllListeners", + value: function removeAllListeners() { + var _this = this; + + var current_subs = this._subs; + this._subs = {}; + Object.keys(current_subs).forEach(function (sub) { + _this._emitter.off(current_subs[sub], sub); + }); + } + }]); + + return SubscriptionTracker; +}(); + +},{}],12:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Var = function () { + function Var(group, name, /*optional*/value) { + _classCallCheck(this, Var); + + this._group = group; + this._name = name; + this._value = value; + this._events = new _events2.default(); + } + + _createClass(Var, [{ + key: "get", + value: function get() { + return this._value; + } + }, { + key: "set", + value: function set(value, /*optional*/event) { + if (this._value === value) { + // Do nothing; the value hasn't changed + return; + } + var oldValue = this._value; + this._value = value; + // Alert JavaScript listeners that the value has changed + var evt = {}; + if (event && (typeof event === "undefined" ? "undefined" : _typeof(event)) === "object") { + for (var k in event) { + if (event.hasOwnProperty(k)) evt[k] = event[k]; + } + } + evt.oldValue = oldValue; + evt.value = value; + this._events.trigger("change", evt, this); + + // TODO: Make this extensible, to let arbitrary back-ends know that + // something has changed + if (global.Shiny && global.Shiny.onInputChange) { + global.Shiny.onInputChange(".clientValue-" + (this._group.name !== null ? this._group.name + "-" : "") + this._name, typeof value === "undefined" ? null : value); + } + } + }, { + key: "on", + value: function on(eventType, listener) { + return this._events.on(eventType, listener); + } + }, { + key: "off", + value: function off(eventType, listener) { + return this._events.off(eventType, listener); + } + }]); + + return Var; +}(); + +exports.default = Var; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./events":1}]},{},[5]) +//# sourceMappingURL=crosstalk.js.map diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js.map b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js.map new file mode 100644 index 0000000..cff94f0 --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js.map @@ -0,0 +1,37 @@ +{ + "version": 3, + "sources": [ + "node_modules/browser-pack/_prelude.js", + "javascript/src/events.js", + "javascript/src/filter.js", + "javascript/src/filterset.js", + "javascript/src/group.js", + "javascript/src/index.js", + "javascript/src/input.js", + "javascript/src/input_checkboxgroup.js", + "javascript/src/input_selectize.js", + "javascript/src/input_slider.js", + "javascript/src/selection.js", + "javascript/src/util.js", + "javascript/src/var.js" + ], + "names": [], + "mappings": "AAAA;;;;;;;;;;;ICAqB,M;AACnB,oBAAc;AAAA;;AACZ,SAAK,MAAL,GAAc,EAAd;AACA,SAAK,IAAL,GAAY,CAAZ;AACD;;;;uBAEE,S,EAAW,Q,EAAU;AACtB,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,UAAI,CAAC,IAAL,EAAW;AACT,eAAO,KAAK,MAAL,CAAY,SAAZ,IAAyB,EAAhC;AACD;AACD,UAAI,MAAM,QAAS,KAAK,IAAL,EAAnB;AACA,WAAK,GAAL,IAAY,QAAZ;AACA,aAAO,GAAP;AACD;;AAED;;;;wBACI,S,EAAW,Q,EAAU;AACvB,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,UAAI,OAAO,QAAP,KAAqB,UAAzB,EAAqC;AACnC,aAAK,IAAI,GAAT,IAAgB,IAAhB,EAAsB;AACpB,cAAI,KAAK,cAAL,CAAoB,GAApB,CAAJ,EAA8B;AAC5B,gBAAI,KAAK,GAAL,MAAc,QAAlB,EAA4B;AAC1B,qBAAO,KAAK,GAAL,CAAP;AACA,qBAAO,GAAP;AACD;AACF;AACF;AACD,eAAO,KAAP;AACD,OAVD,MAUO,IAAI,OAAO,QAAP,KAAqB,QAAzB,EAAmC;AACxC,YAAI,QAAQ,KAAK,QAAL,CAAZ,EAA4B;AAC1B,iBAAO,KAAK,QAAL,CAAP;AACA,iBAAO,QAAP;AACD;AACD,eAAO,KAAP;AACD,OANM,MAMA;AACL,cAAM,IAAI,KAAJ,CAAU,8BAAV,CAAN;AACD;AACF;;;4BAEO,S,EAAW,G,EAAK,O,EAAS;AAC/B,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,WAAK,IAAI,GAAT,IAAgB,IAAhB,EAAsB;AACpB,YAAI,KAAK,cAAL,CAAoB,GAApB,CAAJ,EAA8B;AAC5B,eAAK,GAAL,EAAU,IAAV,CAAe,OAAf,EAAwB,GAAxB;AACD;AACF;AACF;;;;;;kBA/CkB,M;;;;;;;;;;;;ACArB;;;;AACA;;;;AACA;;;;AACA;;IAAY,I;;;;;;;;AAEZ,SAAS,YAAT,CAAsB,KAAtB,EAA6B;AAC3B,MAAI,QAAQ,MAAM,GAAN,CAAU,WAAV,CAAZ;AACA,MAAI,SAAS,MAAM,GAAN,EAAb;AACA,MAAI,CAAC,MAAL,EAAa;AACX,aAAS,yBAAT;AACA,UAAM,GAAN,CAAU,MAAV;AACD;AACD,SAAO,MAAP;AACD;;AAED,IAAI,KAAK,CAAT;AACA,SAAS,MAAT,GAAkB;AAChB,SAAO,IAAP;AACD;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;IAwBa,Y,WAAA,Y;AACX,wBAAY,KAAZ,EAAmB,SAAnB,EAA8B;AAAA;;AAC5B,SAAK,WAAL,GAAmB,sBAAnB;AACA,SAAK,QAAL,GAAgB,IAAI,KAAK,mBAAT,CAA6B,KAAK,WAAlC,CAAhB;;AAEA;AACA,SAAK,MAAL,GAAc,IAAd;AACA;AACA,SAAK,UAAL,GAAkB,IAAlB;AACA;AACA,SAAK,UAAL,GAAkB,IAAlB;AACA;AACA,SAAK,eAAL,GAAuB,IAAvB;;AAEA,SAAK,UAAL,GAAkB,KAAK,MAAL,CAAY,EAAE,QAAQ,IAAV,EAAZ,EAA8B,SAA9B,CAAlB;;AAEA,SAAK,GAAL,GAAW,WAAW,QAAtB;;AAEA,SAAK,QAAL,CAAc,KAAd;AACD;;AAED;;;;;;;;;;;;;;6BAUS,K,EAAO;AAAA;;AACd;AACA,UAAI,KAAK,MAAL,KAAgB,KAApB,EACE;AACF;AACA,UAAI,CAAC,KAAK,MAAN,IAAgB,CAAC,KAArB,EACE;;AAEF,UAAI,KAAK,UAAT,EAAqB;AACnB,aAAK,UAAL,CAAgB,GAAhB,CAAoB,QAApB,EAA8B,KAAK,eAAnC;AACA,aAAK,KAAL;AACA,aAAK,eAAL,GAAuB,IAAvB;AACA,aAAK,UAAL,GAAkB,IAAlB;AACA,aAAK,UAAL,GAAkB,IAAlB;AACD;;AAED,WAAK,MAAL,GAAc,KAAd;;AAEA,UAAI,KAAJ,EAAW;AACT,gBAAQ,qBAAI,KAAJ,CAAR;AACA,aAAK,UAAL,GAAkB,aAAa,KAAb,CAAlB;AACA,aAAK,UAAL,GAAkB,qBAAI,KAAJ,EAAW,GAAX,CAAe,QAAf,CAAlB;AACA,YAAI,MAAM,KAAK,UAAL,CAAgB,EAAhB,CAAmB,QAAnB,EAA6B,UAAC,CAAD,EAAO;AAC5C,gBAAK,WAAL,CAAiB,OAAjB,CAAyB,QAAzB,EAAmC,CAAnC;AACD,SAFS,CAAV;AAGA,aAAK,eAAL,GAAuB,GAAvB;AACD;AACF;;AAED;;;;;;;;oCAKgB,S,EAAW;AACzB,aAAO,KAAK,MAAL,CAAY,EAAZ,EACL,KAAK,UAAL,GAAkB,KAAK,UAAvB,GAAoC,IAD/B,EAEL,YAAY,SAAZ,GAAwB,IAFnB,CAAP;AAGD;;AAED;;;;;;;4BAIQ;AACN,WAAK,QAAL,CAAc,kBAAd;AACA,WAAK,KAAL;AACA,WAAK,QAAL,CAAc,IAAd;AACD;;AAED;;;;;;;;;;;;0BASM,S,EAAW;AACf,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,KAAhB,CAAsB,KAAK,GAA3B;AACA,WAAK,SAAL,CAAe,SAAf;AACD;;AAED;;;;;;;;;;;;;;;;;;;;wBAiBI,I,EAAM,S,EAAW;AACnB,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,MAAhB,CAAuB,KAAK,GAA5B,EAAiC,IAAjC;AACA,WAAK,SAAL,CAAe,SAAf;AACD;;AAED;;;;;;;;;;AASA;;;;;;;;;;uBAUG,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;AAED;;;;;;;;;;;wBAQI,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAP;AACD;;;8BAES,S,EAAW;AACnB,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,GAAhB,CAAoB,KAAK,UAAL,CAAgB,KAApC,EAA2C,KAAK,eAAL,CAAqB,SAArB,CAA3C;AACD;;AAED;;;;;;;;;;;wBApCmB;AACjB,aAAO,KAAK,UAAL,GAAkB,KAAK,UAAL,CAAgB,KAAlC,GAA0C,IAAjD;AACD;;;;;;AA6CH;;;;;;;;;;;;;;;;;;;ACzNA;;;;AAEA,SAAS,iBAAT,CAA2B,CAA3B,EAA8B,CAA9B,EAAiC;AAC/B,MAAI,MAAM,CAAV,EAAa;AACX,WAAO,CAAP;AACD,GAFD,MAEO,IAAI,IAAI,CAAR,EAAW;AAChB,WAAO,CAAC,CAAR;AACD,GAFM,MAEA,IAAI,IAAI,CAAR,EAAW;AAChB,WAAO,CAAP;AACD;AACF;;AAED;;;;IAGqB,S;AACnB,uBAAc;AAAA;;AACZ,SAAK,KAAL;AACD;;;;4BAEO;AACN;AACA,WAAK,QAAL,GAAgB,EAAhB;AACA;AACA,WAAK,KAAL,GAAa,EAAb;AACA,WAAK,MAAL,GAAc,IAAd;AACA,WAAK,cAAL,GAAsB,CAAtB;AACD;;;2BAMM,Q,EAAU,I,EAAM;AACrB,UAAI,SAAS,IAAb,EAAmB;AACjB,eAAO,KAAK,KAAL,CAAW,CAAX,CAAP,CADiB,CACK;AACtB,aAAK,IAAL,CAAU,iBAAV;AACD;;AAJoB,6BAME,2BAAgB,KAAK,QAAL,CAAc,QAAd,CAAhB,EAAyC,IAAzC,CANF;AAAA,UAMhB,KANgB,oBAMhB,KANgB;AAAA,UAMT,OANS,oBAMT,OANS;;AAOrB,WAAK,QAAL,CAAc,QAAd,IAA0B,IAA1B;;AAEA,WAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,MAAM,MAA1B,EAAkC,GAAlC,EAAuC;AACrC,aAAK,KAAL,CAAW,MAAM,CAAN,CAAX,IAAuB,CAAC,KAAK,KAAL,CAAW,MAAM,CAAN,CAAX,KAAwB,CAAzB,IAA8B,CAArD;AACD;AACD,WAAK,IAAI,KAAI,CAAb,EAAgB,KAAI,QAAQ,MAA5B,EAAoC,IAApC,EAAyC;AACvC,aAAK,KAAL,CAAW,QAAQ,EAAR,CAAX;AACD;;AAED,WAAK,YAAL,CAAkB,IAAlB;AACD;;AAED;;;;;;;;mCAKmC;AAAA,UAAtB,IAAsB,uEAAf,KAAK,QAAU;;AACjC,UAAI,cAAc,OAAO,IAAP,CAAY,KAAK,QAAjB,EAA2B,MAA7C;AACA,UAAI,gBAAgB,CAApB,EAAuB;AACrB,aAAK,MAAL,GAAc,IAAd;AACD,OAFD,MAEO;AACL,aAAK,MAAL,GAAc,EAAd;AACA,aAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,cAAI,QAAQ,KAAK,KAAL,CAAW,KAAK,CAAL,CAAX,CAAZ;AACA,cAAI,UAAU,WAAd,EAA2B;AACzB,iBAAK,MAAL,CAAY,IAAZ,CAAiB,KAAK,CAAL,CAAjB;AACD;AACF;AACF;AACF;;;0BAEK,Q,EAAU;AACd,UAAI,OAAO,KAAK,QAAL,CAAc,QAAd,CAAP,KAAoC,WAAxC,EAAqD;AACnD;AACD;;AAED,UAAI,OAAO,KAAK,QAAL,CAAc,QAAd,CAAX;AACA,UAAI,CAAC,IAAL,EAAW;AACT,eAAO,EAAP;AACD;;AAED,WAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,aAAK,KAAL,CAAW,KAAK,CAAL,CAAX;AACD;AACD,aAAO,KAAK,QAAL,CAAc,QAAd,CAAP;;AAEA,WAAK,YAAL;AACD;;;wBA3DW;AACV,aAAO,KAAK,MAAZ;AACD;;;wBA2Dc;AACb,UAAI,UAAU,OAAO,IAAP,CAAY,KAAK,KAAjB,CAAd;AACA,cAAQ,IAAR,CAAa,iBAAb;AACA,aAAO,OAAP;AACD;;;;;;kBA/EkB,S;;;;;;;;;;;;;;kBCRG,K;;AAPxB;;;;;;;;AAEA;AACA;AACA,OAAO,kBAAP,GAA4B,OAAO,kBAAP,IAA6B,EAAzD;AACA,IAAI,SAAS,OAAO,kBAApB;;AAEe,SAAS,KAAT,CAAe,SAAf,EAA0B;AACvC,MAAI,aAAa,OAAO,SAAP,KAAsB,QAAvC,EAAiD;AAC/C,QAAI,CAAC,OAAO,cAAP,CAAsB,SAAtB,CAAL,EAAuC;AACrC,aAAO,SAAP,IAAoB,IAAI,KAAJ,CAAU,SAAV,CAApB;AACD;AACD,WAAO,OAAO,SAAP,CAAP;AACD,GALD,MAKO,IAAI,QAAO,SAAP,yCAAO,SAAP,OAAsB,QAAtB,IAAkC,UAAU,KAA5C,IAAqD,UAAU,GAAnE,EAAwE;AAC7E;AACA,WAAO,SAAP;AACD,GAHM,MAGA,IAAI,MAAM,OAAN,CAAc,SAAd,KACP,UAAU,MAAV,IAAoB,CADb,IAEP,OAAO,UAAU,CAAV,CAAP,KAAyB,QAFtB,EAEgC;AACrC,WAAO,MAAM,UAAU,CAAV,CAAN,CAAP;AACD,GAJM,MAIA;AACL,UAAM,IAAI,KAAJ,CAAU,4BAAV,CAAN;AACD;AACF;;IAEK,K;AACJ,iBAAY,IAAZ,EAAkB;AAAA;;AAChB,SAAK,IAAL,GAAY,IAAZ;AACA,SAAK,KAAL,GAAa,EAAb;AACD;;;;yBAEG,I,EAAM;AACR,UAAI,CAAC,IAAD,IAAS,OAAO,IAAP,KAAiB,QAA9B,EAAwC;AACtC,cAAM,IAAI,KAAJ,CAAU,kBAAV,CAAN;AACD;;AAED,UAAI,CAAC,KAAK,KAAL,CAAW,cAAX,CAA0B,IAA1B,CAAL,EACE,KAAK,KAAL,CAAW,IAAX,IAAmB,kBAAQ,IAAR,EAAc,IAAd,CAAnB;AACF,aAAO,KAAK,KAAL,CAAW,IAAX,CAAP;AACD;;;wBAEG,I,EAAM;AACR,UAAI,CAAC,IAAD,IAAS,OAAO,IAAP,KAAiB,QAA9B,EAAwC;AACtC,cAAM,IAAI,KAAJ,CAAU,kBAAV,CAAN;AACD;;AAED,aAAO,KAAK,KAAL,CAAW,cAAX,CAA0B,IAA1B,CAAP;AACD;;;;;;;;;;;;;;;;AC/CH;;;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEA,IAAM,eAAe,qBAAM,SAAN,CAArB;;AAEA,SAAS,IAAT,CAAc,IAAd,EAAoB;AAClB,SAAO,aAAa,GAAb,CAAiB,IAAjB,CAAP;AACD;;AAED,SAAS,GAAT,CAAa,IAAb,EAAmB;AACjB,SAAO,aAAa,GAAb,CAAiB,IAAjB,CAAP;AACD;;AAED,IAAI,OAAO,KAAX,EAAkB;AAChB,SAAO,KAAP,CAAa,uBAAb,CAAqC,qBAArC,EAA4D,UAAS,OAAT,EAAkB;AAC5E,QAAI,OAAO,QAAQ,KAAf,KAA0B,QAA9B,EAAwC;AACtC,2BAAM,QAAQ,KAAd,EAAqB,GAArB,CAAyB,QAAQ,IAAjC,EAAuC,GAAvC,CAA2C,QAAQ,KAAnD;AACD,KAFD,MAEO;AACL,WAAK,QAAQ,IAAb,EAAmB,GAAnB,CAAuB,QAAQ,KAA/B;AACD;AACF,GAND;AAOD;;AAED,IAAM,YAAY;AAChB,wBADgB;AAEhB,OAAK,IAFW;AAGhB,OAAK,GAHW;AAIhB,6CAJgB;AAKhB,oCALgB;AAMhB;AANgB,CAAlB;;AASA;;;kBAGe,S;;AACf,OAAO,SAAP,GAAmB,SAAnB;;;;;;;;;;;QCrCgB,Q,GAAA,Q;QAWA,I,GAAA,I;AAfhB,IAAI,IAAI,OAAO,MAAf;;AAEA,IAAI,WAAW,EAAf;;AAEO,SAAS,QAAT,CAAkB,GAAlB,EAAuB;AAC5B,WAAS,IAAI,SAAb,IAA0B,GAA1B;AACA,MAAI,OAAO,QAAP,IAAmB,OAAO,QAAP,CAAgB,UAAhB,KAA+B,UAAtD,EAAkE;AAChE,MAAE,YAAM;AACN;AACD,KAFD;AAGD,GAJD,MAIO,IAAI,OAAO,QAAX,EAAqB;AAC1B,eAAW,IAAX,EAAiB,GAAjB;AACD;AACF;;AAEM,SAAS,IAAT,GAAgB;AACrB,SAAO,IAAP,CAAY,QAAZ,EAAsB,OAAtB,CAA8B,UAAS,SAAT,EAAoB;AAChD,QAAI,UAAU,SAAS,SAAT,CAAd;AACA,MAAE,MAAM,QAAQ,SAAhB,EAA2B,GAA3B,CAA+B,wBAA/B,EAAyD,IAAzD,CAA8D,UAAS,CAAT,EAAY,EAAZ,EAAgB;AAC5E,mBAAa,OAAb,EAAsB,EAAtB;AACD,KAFD;AAGD,GALD;AAMD;;AAED;AACA,SAAS,OAAT,CAAiB,GAAjB,EAAsB;AACpB,SAAO,IAAI,OAAJ,CAAY,uCAAZ,EAAqD,MAArD,CAAP;AACD;;AAED,SAAS,MAAT,CAAgB,EAAhB,EAAoB;AAClB,MAAI,MAAM,EAAE,EAAF,CAAV;AACA,SAAO,IAAP,CAAY,QAAZ,EAAsB,OAAtB,CAA8B,UAAS,SAAT,EAAoB;AAChD,QAAI,IAAI,QAAJ,CAAa,SAAb,KAA2B,CAAC,IAAI,QAAJ,CAAa,uBAAb,CAAhC,EAAuE;AACrE,UAAI,UAAU,SAAS,SAAT,CAAd;AACA,mBAAa,OAAb,EAAsB,EAAtB;AACD;AACF,GALD;AAMD;;AAED,SAAS,YAAT,CAAsB,OAAtB,EAA+B,EAA/B,EAAmC;AACjC,MAAI,SAAS,EAAE,EAAF,EAAM,IAAN,CAAW,+CAA+C,QAAQ,GAAG,EAAX,CAA/C,GAAgE,IAA3E,CAAb;AACA,MAAI,OAAO,KAAK,KAAL,CAAW,OAAO,CAAP,EAAU,SAArB,CAAX;;AAEA,MAAI,WAAW,QAAQ,OAAR,CAAgB,EAAhB,EAAoB,IAApB,CAAf;AACA,IAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,QAAjC;AACA,IAAE,EAAF,EAAM,QAAN,CAAe,uBAAf;AACD;;AAED,IAAI,OAAO,KAAX,EAAkB;AAChB,MAAI,eAAe,IAAI,OAAO,KAAP,CAAa,YAAjB,EAAnB;AACA,MAAI,KAAI,OAAO,MAAf;AACA,KAAE,MAAF,CAAS,YAAT,EAAuB;AACrB,UAAM,cAAS,KAAT,EAAgB;AACpB,aAAO,GAAE,KAAF,EAAS,IAAT,CAAc,kBAAd,CAAP;AACD,KAHoB;AAIrB,gBAAY,oBAAS,EAAT,EAAa;AACvB,UAAI,CAAC,GAAE,EAAF,EAAM,QAAN,CAAe,uBAAf,CAAL,EAA8C;AAC5C,eAAO,EAAP;AACD;AACF,KARoB;AASrB,WAAO,eAAS,EAAT,EAAa;AAClB,aAAO,GAAG,EAAV;AACD,KAXoB;AAYrB,cAAU,kBAAS,EAAT,EAAa,CAEtB,CAdoB;AAerB,cAAU,kBAAS,EAAT,EAAa,KAAb,EAAoB,CAE7B,CAjBoB;AAkBrB,oBAAgB,wBAAS,EAAT,EAAa,IAAb,EAAmB,CAElC,CApBoB;AAqBrB,eAAW,mBAAS,EAAT,EAAa,QAAb,EAAuB;AAChC,SAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,MAAjC;AACD,KAvBoB;AAwBrB,iBAAa,qBAAS,EAAT,EAAa;AACxB,SAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,OAAjC;AACD;AA1BoB,GAAvB;AA4BA,SAAO,KAAP,CAAa,aAAb,CAA2B,QAA3B,CAAoC,YAApC,EAAkD,wBAAlD;AACD;;;;;;;;AChFD;;IAAY,K;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,+BADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;AAIA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,sBAAJ;AACA,QAAI,MAAM,EAAE,EAAF,CAAV;AACA,QAAI,EAAJ,CAAO,QAAP,EAAiB,wBAAjB,EAA2C,YAAW;AACpD,UAAI,UAAU,IAAI,IAAJ,CAAS,gCAAT,CAAd;AACA,UAAI,QAAQ,MAAR,KAAmB,CAAvB,EAA0B;AACxB,wBAAgB,IAAhB;AACA,iBAAS,KAAT;AACD,OAHD,MAGO;AACL,YAAI,OAAO,EAAX;AACA,gBAAQ,IAAR,CAAa,YAAW;AACtB,eAAK,GAAL,CAAS,KAAK,KAAd,EAAqB,OAArB,CAA6B,UAAS,GAAT,EAAc;AACzC,iBAAK,GAAL,IAAY,IAAZ;AACD,WAFD;AAGD,SAJD;AAKA,YAAI,WAAW,OAAO,IAAP,CAAY,IAAZ,CAAf;AACA,iBAAS,IAAT;AACA,wBAAgB,QAAhB;AACA,iBAAS,GAAT,CAAa,QAAb;AACD;AACF,KAjBD;;AAmBA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AAxCY,CAAf;;;;;;;;ACLA;;IAAY,K;;AACZ;;IAAY,I;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,wBADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;;;AAMA,QAAI,QAAQ,CAAC,EAAC,OAAO,EAAR,EAAY,OAAO,OAAnB,EAAD,CAAZ;AACA,QAAI,QAAQ,KAAK,aAAL,CAAmB,KAAK,KAAxB,CAAZ;AACA,QAAI,OAAO;AACT,eAAS,MAAM,MAAN,CAAa,KAAb,CADA;AAET,kBAAY,OAFH;AAGT,kBAAY,OAHH;AAIT,mBAAa;AAJJ,KAAX;;AAOA,QAAI,SAAS,EAAE,EAAF,EAAM,IAAN,CAAW,QAAX,EAAqB,CAArB,CAAb;;AAEA,QAAI,YAAY,EAAE,MAAF,EAAU,SAAV,CAAoB,IAApB,EAA0B,CAA1B,EAA6B,SAA7C;;AAEA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,sBAAJ;AACA,cAAU,EAAV,CAAa,QAAb,EAAuB,YAAW;AAChC,UAAI,UAAU,KAAV,CAAgB,MAAhB,KAA2B,CAA/B,EAAkC;AAChC,wBAAgB,IAAhB;AACA,iBAAS,KAAT;AACD,OAHD,MAGO;AACL,YAAI,OAAO,EAAX;AACA,kBAAU,KAAV,CAAgB,OAAhB,CAAwB,UAAS,KAAT,EAAgB;AACtC,eAAK,GAAL,CAAS,KAAT,EAAgB,OAAhB,CAAwB,UAAS,GAAT,EAAc;AACpC,iBAAK,GAAL,IAAY,IAAZ;AACD,WAFD;AAGD,SAJD;AAKA,YAAI,WAAW,OAAO,IAAP,CAAY,IAAZ,CAAf;AACA,iBAAS,IAAT;AACA,wBAAgB,QAAhB;AACA,iBAAS,GAAT,CAAa,QAAb;AACD;AACF,KAhBD;;AAkBA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AArDY,CAAf;;;;;;;;;;ACNA;;IAAY,K;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;AACA,IAAI,WAAW,OAAO,QAAtB;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,wBADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;AAIA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,OAAO,EAAX;AACA,QAAI,MAAM,EAAE,EAAF,EAAM,IAAN,CAAW,OAAX,CAAV;AACA,QAAI,WAAW,IAAI,IAAJ,CAAS,WAAT,CAAf;AACA,QAAI,aAAa,IAAI,IAAJ,CAAS,aAAT,CAAjB;AACA,QAAI,QAAQ,IAAI,IAAJ,CAAS,OAAT,CAAZ;AACA,QAAI,sBAAJ;;AAEA;AACA,QAAI,aAAa,MAAjB,EAAyB;AACvB,sBAAgB,SAAS,GAAT,EAAhB;AACA,WAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,eAAO,cAAc,UAAd,EAA0B,IAAI,IAAJ,CAAS,GAAT,CAA1B,CAAP;AACD,OAFD;AAID,KAND,MAMO,IAAI,aAAa,UAAjB,EAA6B;AAClC,UAAI,WAAW,IAAI,IAAJ,CAAS,UAAT,CAAf;AACA,UAAI,QAAJ,EACE,gBAAgB,SAAS,QAAT,CAAkB,QAAlB,CAAhB,CADF,KAGE,gBAAgB,QAAhB;;AAEF,WAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,eAAO,cAAc,UAAd,EAA0B,IAAI,IAAJ,CAAS,GAAT,CAA1B,CAAP;AACD,OAFD;AAGD,KAVM,MAUA,IAAI,aAAa,QAAjB,EAA2B;AAChC,UAAI,OAAO,KAAP,KAAiB,WAArB,EACE,KAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,YAAI,SAAS,KAAK,GAAL,CAAS,EAAT,EAAa,KAAb,CAAb;AACA,eAAO,KAAK,KAAL,CAAW,MAAM,MAAjB,IAA2B,MAAlC;AACD,OAHD;AAIH;;AAED,QAAI,cAAJ,CAAmB,IAAnB;;AAEA,aAAS,QAAT,GAAoB;AAClB,UAAI,SAAS,IAAI,IAAJ,CAAS,gBAAT,EAA2B,MAAxC;;AAEA;AACA,UAAI,gBAAJ;AACA,UAAI,WAAW,IAAI,IAAJ,CAAS,WAAT,CAAf;AACA,UAAI,aAAa,MAAjB,EAAyB;AACvB,kBAAU,iBAAS,GAAT,EAAc;AACtB,iBAAO,cAAc,IAAI,IAAJ,CAAS,CAAC,GAAV,CAAd,CAAP;AACD,SAFD;AAGD,OAJD,MAIO,IAAI,aAAa,UAAjB,EAA6B;AAClC,kBAAU,iBAAS,GAAT,EAAc;AACtB;AACA,iBAAO,CAAC,GAAD,GAAO,IAAd;AACD,SAHD;AAID,OALM,MAKA;AACL,kBAAU,iBAAS,GAAT,EAAc;AAAE,iBAAO,CAAC,GAAR;AAAc,SAAxC;AACD;;AAED,UAAI,IAAI,IAAJ,CAAS,gBAAT,EAA2B,OAA3B,CAAmC,IAAnC,KAA4C,QAAhD,EAA0D;AACxD,eAAO,CAAC,QAAQ,OAAO,IAAf,CAAD,EAAuB,QAAQ,OAAO,EAAf,CAAvB,CAAP;AACD,OAFD,MAEO;AACL,eAAO,QAAQ,OAAO,IAAf,CAAP;AACD;AACF;;AAED,QAAI,gBAAgB,IAApB;;AAEA,QAAI,EAAJ,CAAO,6BAAP,EAAsC,UAAS,KAAT,EAAgB;AACpD,UAAI,CAAC,IAAI,IAAJ,CAAS,UAAT,CAAD,IAAyB,CAAC,IAAI,IAAJ,CAAS,WAAT,CAA9B,EAAqD;AAAA,wBAClC,UADkC;AAAA;AAAA,YAC9C,IAD8C;AAAA,YACxC,EADwC;;AAEnD,YAAI,OAAO,EAAX;AACA,aAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAL,CAAY,MAAhC,EAAwC,GAAxC,EAA6C;AAC3C,cAAI,MAAM,KAAK,MAAL,CAAY,CAAZ,CAAV;AACA,cAAI,OAAO,IAAP,IAAe,OAAO,EAA1B,EAA8B;AAC5B,iBAAK,IAAL,CAAU,KAAK,IAAL,CAAU,CAAV,CAAV;AACD;AACF;AACD,aAAK,IAAL;AACA,iBAAS,GAAT,CAAa,IAAb;AACA,wBAAgB,IAAhB;AACD;AACF,KAdD;;AAiBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AApHY,CAAf;;AAwHA;AACA,SAAS,QAAT,CAAkB,CAAlB,EAAqB,MAArB,EAA6B;AAC3B,MAAI,MAAM,EAAE,QAAF,EAAV;AACA,SAAO,IAAI,MAAJ,GAAa,MAApB;AACE,UAAM,MAAM,GAAZ;AADF,GAEA,OAAO,GAAP;AACD;;AAED;AACA;AACA,SAAS,aAAT,CAAuB,IAAvB,EAA6B;AAC3B,MAAI,gBAAgB,IAApB,EAA0B;AACxB,WAAO,KAAK,cAAL,KAAwB,GAAxB,GACA,SAAS,KAAK,WAAL,KAAmB,CAA5B,EAA+B,CAA/B,CADA,GACoC,GADpC,GAEA,SAAS,KAAK,UAAL,EAAT,EAA4B,CAA5B,CAFP;AAID,GALD,MAKO;AACL,WAAO,IAAP;AACD;AACF;;;;;;;;;;;;;;ACjJD;;;;AACA;;;;AACA;;IAAY,I;;;;;;;;AAEZ;;;;;;;;;;;;;;;;IAgBa,e,WAAA,e;AAEX,6BAA4C;AAAA,QAAhC,KAAgC,uEAAxB,IAAwB;AAAA,QAAlB,SAAkB,uEAAN,IAAM;;AAAA;;AAC1C,SAAK,WAAL,GAAmB,sBAAnB;AACA,SAAK,QAAL,GAAgB,IAAI,KAAK,mBAAT,CAA6B,KAAK,WAAlC,CAAhB;;AAEA;AACA,SAAK,MAAL,GAAc,IAAd;AACA;AACA,SAAK,IAAL,GAAY,IAAZ;AACA;AACA,SAAK,eAAL,GAAuB,IAAvB;;AAEA,SAAK,UAAL,GAAkB,KAAK,MAAL,CAAY,EAAE,QAAQ,IAAV,EAAZ,EAA8B,SAA9B,CAAlB;;AAEA,SAAK,QAAL,CAAc,KAAd;AACD;;AAED;;;;;;;;;;;;;;;;;6BAaS,K,EAAO;AAAA;;AACd;AACA,UAAI,KAAK,MAAL,KAAgB,KAApB,EACE;AACF;AACA,UAAI,CAAC,KAAK,MAAN,IAAgB,CAAC,KAArB,EACE;;AAEF,UAAI,KAAK,IAAT,EAAe;AACb,aAAK,IAAL,CAAU,GAAV,CAAc,QAAd,EAAwB,KAAK,eAA7B;AACA,aAAK,IAAL,GAAY,IAAZ;AACA,aAAK,eAAL,GAAuB,IAAvB;AACD;;AAED,WAAK,MAAL,GAAc,KAAd;;AAEA,UAAI,KAAJ,EAAW;AACT,aAAK,IAAL,GAAY,qBAAI,KAAJ,EAAW,GAAX,CAAe,WAAf,CAAZ;AACA,YAAI,MAAM,KAAK,IAAL,CAAU,EAAV,CAAa,QAAb,EAAuB,UAAC,CAAD,EAAO;AACtC,gBAAK,WAAL,CAAiB,OAAjB,CAAyB,QAAzB,EAAmC,CAAnC;AACD,SAFS,CAAV;AAGA,aAAK,eAAL,GAAuB,GAAvB;AACD;AACF;;AAED;;;;;;;;;;;;;;;AAcA;;;;;oCAKgB,S,EAAW;AACzB;AACA,aAAO,KAAK,MAAL,CAAY,EAAZ,EACL,KAAK,UAAL,GAAkB,KAAK,UAAvB,GAAoC,IAD/B,EAEL,YAAY,SAAZ,GAAwB,IAFnB,CAAP;AAGD;;AAED;;;;;;;;;;;;;;;wBAYI,Y,EAAc,S,EAAW;AAC3B,UAAI,KAAK,IAAT,EACE,KAAK,IAAL,CAAU,GAAV,CAAc,YAAd,EAA4B,KAAK,eAAL,CAAqB,SAArB,CAA5B;AACH;;AAED;;;;;;;;;;;;;0BAUM,S,EAAW;AACf,UAAI,KAAK,IAAT,EACE,KAAK,GAAL,CAAS,KAAK,CAAd,EAAiB,KAAK,eAAL,CAAqB,SAArB,CAAjB;AACH;;AAED;;;;;;;;;;;;;uBAUG,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;AAED;;;;;;;;;;;wBAQI,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAP;AACD;;AAED;;;;;;;;4BAKQ;AACN,WAAK,QAAL,CAAc,kBAAd;AACA,WAAK,QAAL,CAAc,IAAd;AACD;;;wBAlFW;AACV,aAAO,KAAK,IAAL,GAAY,KAAK,IAAL,CAAU,GAAV,EAAZ,GAA8B,IAArC;AACD;;;;;;AAmFH;;;;;;;;;AASA;;;;;;;;;;;;;;;;;;;;;QCpLgB,M,GAAA,M;QAeA,W,GAAA,W;QAQA,e,GAAA,e;QAoCA,a,GAAA,a;;;;AA3DT,SAAS,MAAT,CAAgB,MAAhB,EAAoC;AAAA,oCAAT,OAAS;AAAT,WAAS;AAAA;;AACzC,OAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,QAAQ,MAA5B,EAAoC,GAApC,EAAyC;AACvC,QAAI,MAAM,QAAQ,CAAR,CAAV;AACA,QAAI,OAAO,GAAP,KAAgB,WAAhB,IAA+B,QAAQ,IAA3C,EACE;;AAEF,SAAK,IAAI,GAAT,IAAgB,GAAhB,EAAqB;AACnB,UAAI,IAAI,cAAJ,CAAmB,GAAnB,CAAJ,EAA6B;AAC3B,eAAO,GAAP,IAAc,IAAI,GAAJ,CAAd;AACD;AACF;AACF;AACD,SAAO,MAAP;AACD;;AAEM,SAAS,WAAT,CAAqB,IAArB,EAA2B;AAChC,OAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,QAAI,KAAK,CAAL,KAAW,KAAK,IAAE,CAAP,CAAf,EAA0B;AACxB,YAAM,IAAI,KAAJ,CAAU,0CAAV,CAAN;AACD;AACF;AACF;;AAEM,SAAS,eAAT,CAAyB,CAAzB,EAA4B,CAA5B,EAA+B;AACpC,MAAI,MAAM,CAAV;AACA,MAAI,MAAM,CAAV;;AAEA,MAAI,CAAC,CAAL,EAAQ,IAAI,EAAJ;AACR,MAAI,CAAC,CAAL,EAAQ,IAAI,EAAJ;;AAER,MAAI,SAAS,EAAb;AACA,MAAI,SAAS,EAAb;;AAEA,cAAY,CAAZ;AACA,cAAY,CAAZ;;AAEA,SAAO,MAAM,EAAE,MAAR,IAAkB,MAAM,EAAE,MAAjC,EAAyC;AACvC,QAAI,EAAE,GAAF,MAAW,EAAE,GAAF,CAAf,EAAuB;AACrB;AACA;AACD,KAHD,MAGO,IAAI,EAAE,GAAF,IAAS,EAAE,GAAF,CAAb,EAAqB;AAC1B,aAAO,IAAP,CAAY,EAAE,KAAF,CAAZ;AACD,KAFM,MAEA;AACL,aAAO,IAAP,CAAY,EAAE,KAAF,CAAZ;AACD;AACF;;AAED,MAAI,MAAM,EAAE,MAAZ,EACE,SAAS,OAAO,MAAP,CAAc,EAAE,KAAF,CAAQ,GAAR,CAAd,CAAT;AACF,MAAI,MAAM,EAAE,MAAZ,EACE,SAAS,OAAO,MAAP,CAAc,EAAE,KAAF,CAAQ,GAAR,CAAd,CAAT;AACF,SAAO;AACL,aAAS,MADJ;AAEL,WAAO;AAFF,GAAP;AAID;;AAED;AACA;AACO,SAAS,aAAT,CAAuB,EAAvB,EAA2B;AAChC,MAAI,QAAQ,EAAZ;AACA,MAAI,eAAJ;AACA,OAAK,IAAI,IAAT,IAAiB,EAAjB,EAAqB;AACnB,QAAI,GAAG,cAAH,CAAkB,IAAlB,CAAJ,EACE,MAAM,IAAN,CAAW,IAAX;AACF,QAAI,QAAO,GAAG,IAAH,CAAP,MAAqB,QAArB,IAAiC,OAAO,GAAG,IAAH,EAAS,MAAhB,KAA4B,WAAjE,EAA8E;AAC5E,YAAM,IAAI,KAAJ,CAAU,2BAAV,CAAN;AACD,KAFD,MAEO,IAAI,OAAO,MAAP,KAAmB,WAAnB,IAAkC,WAAW,GAAG,IAAH,EAAS,MAA1D,EAAkE;AACvE,YAAM,IAAI,KAAJ,CAAU,8CAAV,CAAN;AACD;AACD,aAAS,GAAG,IAAH,EAAS,MAAlB;AACD;AACD,MAAI,UAAU,EAAd;AACA,MAAI,aAAJ;AACA,OAAK,IAAI,MAAM,CAAf,EAAkB,MAAM,MAAxB,EAAgC,KAAhC,EAAuC;AACrC,WAAO,EAAP;AACA,SAAK,IAAI,MAAM,CAAf,EAAkB,MAAM,MAAM,MAA9B,EAAsC,KAAtC,EAA6C;AAC3C,WAAK,MAAM,GAAN,CAAL,IAAmB,GAAG,MAAM,GAAN,CAAH,EAAe,GAAf,CAAnB;AACD;AACD,YAAQ,IAAR,CAAa,IAAb;AACD;AACD,SAAO,OAAP;AACD;;AAED;;;;;;;IAMa,mB,WAAA,mB;AACX,+BAAY,OAAZ,EAAqB;AAAA;;AACnB,SAAK,QAAL,GAAgB,OAAhB;AACA,SAAK,KAAL,GAAa,EAAb;AACD;;;;uBAEE,S,EAAW,Q,EAAU;AACtB,UAAI,MAAM,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAV;AACA,WAAK,KAAL,CAAW,GAAX,IAAkB,SAAlB;AACA,aAAO,GAAP;AACD;;;wBAEG,S,EAAW,Q,EAAU;AACvB,UAAI,MAAM,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAV;AACA,UAAI,GAAJ,EAAS;AACP,eAAO,KAAK,KAAL,CAAW,GAAX,CAAP;AACD;AACD,aAAO,GAAP;AACD;;;yCAEoB;AAAA;;AACnB,UAAI,eAAe,KAAK,KAAxB;AACA,WAAK,KAAL,GAAa,EAAb;AACA,aAAO,IAAP,CAAY,YAAZ,EAA0B,OAA1B,CAAkC,UAAC,GAAD,EAAS;AACzC,cAAK,QAAL,CAAc,GAAd,CAAkB,aAAa,GAAb,CAAlB,EAAqC,GAArC;AACD,OAFD;AAGD;;;;;;;;;;;;;;;;;;ACpHH;;;;;;;;IAEqB,G;AACnB,eAAY,KAAZ,EAAmB,IAAnB,EAAyB,YAAa,KAAtC,EAA6C;AAAA;;AAC3C,SAAK,MAAL,GAAc,KAAd;AACA,SAAK,KAAL,GAAa,IAAb;AACA,SAAK,MAAL,GAAc,KAAd;AACA,SAAK,OAAL,GAAe,sBAAf;AACD;;;;0BAEK;AACJ,aAAO,KAAK,MAAZ;AACD;;;wBAEG,K,EAAO,YAAa,K,EAAO;AAC7B,UAAI,KAAK,MAAL,KAAgB,KAApB,EAA2B;AACzB;AACA;AACD;AACD,UAAI,WAAW,KAAK,MAApB;AACA,WAAK,MAAL,GAAc,KAAd;AACA;AACA,UAAI,MAAM,EAAV;AACA,UAAI,SAAS,QAAO,KAAP,yCAAO,KAAP,OAAkB,QAA/B,EAAyC;AACvC,aAAK,IAAI,CAAT,IAAc,KAAd,EAAqB;AACnB,cAAI,MAAM,cAAN,CAAqB,CAArB,CAAJ,EACE,IAAI,CAAJ,IAAS,MAAM,CAAN,CAAT;AACH;AACF;AACD,UAAI,QAAJ,GAAe,QAAf;AACA,UAAI,KAAJ,GAAY,KAAZ;AACA,WAAK,OAAL,CAAa,OAAb,CAAqB,QAArB,EAA+B,GAA/B,EAAoC,IAApC;;AAEA;AACA;AACA,UAAI,OAAO,KAAP,IAAgB,OAAO,KAAP,CAAa,aAAjC,EAAgD;AAC9C,eAAO,KAAP,CAAa,aAAb,CACE,mBACG,KAAK,MAAL,CAAY,IAAZ,KAAqB,IAArB,GAA4B,KAAK,MAAL,CAAY,IAAZ,GAAmB,GAA/C,GAAqD,EADxD,IAEE,KAAK,KAHT,EAIE,OAAO,KAAP,KAAkB,WAAlB,GAAgC,IAAhC,GAAuC,KAJzC;AAMD;AACF;;;uBAEE,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,OAAL,CAAa,EAAb,CAAgB,SAAhB,EAA2B,QAA3B,CAAP;AACD;;;wBAEG,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,OAAL,CAAa,GAAb,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;;;;;kBAjDkB,G", + "file": "generated.js", + "sourceRoot": "", + "sourcesContent": [ + "(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n", + "import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n", + "import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n", + "import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n", + "let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n", + "import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n", + "export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n", + "import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n" + ] +} \ No newline at end of file diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.min.js b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.min.js new file mode 100644 index 0000000..b7ec0ac --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.min.js @@ -0,0 +1,2 @@ +!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n","import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n","import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n","import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n","let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n","import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n","export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n","import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n"]} \ No newline at end of file diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/scss/crosstalk.scss b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/scss/crosstalk.scss new file mode 100644 index 0000000..3566561 --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/scss/crosstalk.scss @@ -0,0 +1,75 @@ +/* Adjust margins outwards, so column contents line up with the edges of the + parent of container-fluid. */ +.container-fluid.crosstalk-bscols { + margin-left: -30px; + margin-right: -30px; + white-space: normal; +} + +/* But don't adjust the margins outwards if we're directly under the body, + i.e. we were the top-level of something at the console. */ +body > .container-fluid.crosstalk-bscols { + margin-left: auto; + margin-right: auto; +} + +.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: inline-block; + padding-right: 12px; + vertical-align: top; +} + +@media only screen and (max-width:480px) { + .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: block; + padding-right: inherit; + } +} + +/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */ +.crosstalk-input { + margin-bottom: 15px; /* a la .form-group */ + .control-label { + margin-bottom: 0; + vertical-align: middle; + } + input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px; + line-height: normal; + } + .checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; + } + .checkbox > label{ + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + cursor: pointer; + } + .checkbox input[type="checkbox"], + .checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 2px; + margin-left: -20px; + } + .checkbox + .checkbox { + margin-top: -5px; + } + .checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + vertical-align: middle; + cursor: pointer; + } + .checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; + } +} diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-binding/datatables.js b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-binding/datatables.js new file mode 100644 index 0000000..765b53c --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-binding/datatables.js @@ -0,0 +1,1539 @@ +(function() { + +// some helper functions: using a global object DTWidget so that it can be used +// in JS() code, e.g. datatable(options = list(foo = JS('code'))); unlike R's +// dynamic scoping, when 'code' is eval'ed, JavaScript does not know objects +// from the "parent frame", e.g. JS('DTWidget') will not work unless it was made +// a global object +var DTWidget = {}; + +// 123456666.7890 -> 123,456,666.7890 +var markInterval = function(d, digits, interval, mark, decMark, precision) { + x = precision ? d.toPrecision(digits) : d.toFixed(digits); + if (!/^-?[\d.]+$/.test(x)) return x; + var xv = x.split('.'); + if (xv.length > 2) return x; // should have at most one decimal point + xv[0] = xv[0].replace(new RegExp('\\B(?=(\\d{' + interval + '})+(?!\\d))', 'g'), mark); + return xv.join(decMark); +}; + +DTWidget.formatCurrency = function(data, currency, digits, interval, mark, decMark, before, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + var res = markInterval(d, digits, interval, mark, decMark); + res = before ? (/^-/.test(res) ? '-' + currency + res.replace(/^-/, '') : currency + res) : + res + currency; + return res; +}; + +DTWidget.formatString = function(data, prefix, suffix) { + var d = data; + if (d === null) return ''; + return prefix + d + suffix; +}; + +DTWidget.formatPercentage = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d * 100, digits, interval, mark, decMark) + '%'; +}; + +DTWidget.formatRound = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark); +}; + +DTWidget.formatSignif = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark, true); +}; + +DTWidget.formatDate = function(data, method, params) { + var d = data; + if (d === null) return ''; + // (new Date('2015-10-28')).toDateString() may return 2015-10-27 because the + // actual time created could be like 'Tue Oct 27 2015 19:00:00 GMT-0500 (CDT)', + // i.e. the date-only string is treated as UTC time instead of local time + if ((method === 'toDateString' || method === 'toLocaleDateString') && /^\d{4,}\D\d{2}\D\d{2}$/.test(d)) { + d = d.split(/\D/); + d = new Date(d[0], d[1] - 1, d[2]); + } else { + d = new Date(d); + } + return d[method].apply(d, params); +}; + +window.DTWidget = DTWidget; + +// A helper function to update the properties of existing filters +var setFilterProps = function(td, props) { + // Update enabled/disabled state + var $input = $(td).find('input').first(); + var searchable = $input.data('searchable'); + $input.prop('disabled', !searchable || props.disabled); + + // Based on the filter type, set its new values + var type = td.getAttribute('data-type'); + if (['factor', 'logical'].includes(type)) { + // Reformat the new dropdown options for use with selectize + var new_vals = props.params.options.map(function(item) { + return { text: item, value: item }; + }); + + // Find the selectize object + var dropdown = $(td).find('.selectized').eq(0)[0].selectize; + + // Note the current values + var old_vals = dropdown.getValue(); + + // Remove the existing values + dropdown.clearOptions(); + + // Add the new options + dropdown.addOption(new_vals); + + // Preserve the existing values + dropdown.setValue(old_vals); + + } else if (['number', 'integer', 'date', 'time'].includes(type)) { + // Apply internal scaling to new limits. Updating scale not yet implemented. + var slider = $(td).find('.noUi-target').eq(0); + var scale = Math.pow(10, Math.max(0, +slider.data('scale') || 0)); + var new_vals = [props.params.min * scale, props.params.max * scale]; + + // Note what the new limits will be just for this filter + var new_lims = new_vals.slice(); + + // Determine the current values and limits + var old_vals = slider.val().map(Number); + var old_lims = slider.noUiSlider('options').range; + old_lims = [old_lims.min, old_lims.max]; + + // Preserve the current values if filters have been applied; otherwise, apply no filtering + if (old_vals[0] != old_lims[0]) { + new_vals[0] = Math.max(old_vals[0], new_vals[0]); + } + + if (old_vals[1] != old_lims[1]) { + new_vals[1] = Math.min(old_vals[1], new_vals[1]); + } + + // Update the endpoints of the slider + slider.noUiSlider({ + start: new_vals, + range: {'min': new_lims[0], 'max': new_lims[1]} + }, true); + } +}; + +var transposeArray2D = function(a) { + return a.length === 0 ? a : HTMLWidgets.transposeArray2D(a); +}; + +var crosstalkPluginsInstalled = false; + +function maybeInstallCrosstalkPlugins() { + if (crosstalkPluginsInstalled) + return; + crosstalkPluginsInstalled = true; + + $.fn.dataTable.ext.afnFiltering.push( + function(oSettings, aData, iDataIndex) { + var ctfilter = oSettings.nTable.ctfilter; + if (ctfilter && !ctfilter[iDataIndex]) + return false; + + var ctselect = oSettings.nTable.ctselect; + if (ctselect && !ctselect[iDataIndex]) + return false; + + return true; + } + ); +} + +HTMLWidgets.widget({ + name: "datatables", + type: "output", + renderOnNullValue: true, + initialize: function(el, width, height) { + // in order that the type=number inputs return a number + $.valHooks.number = { + get: function(el) { + var value = parseFloat(el.value); + return isNaN(value) ? "" : value; + } + }; + $(el).html(' '); + return { + data: null, + ctfilterHandle: new crosstalk.FilterHandle(), + ctfilterSubscription: null, + ctselectHandle: new crosstalk.SelectionHandle(), + ctselectSubscription: null + }; + }, + renderValue: function(el, data, instance) { + if (el.offsetWidth === 0 || el.offsetHeight === 0) { + instance.data = data; + return; + } + instance.data = null; + var $el = $(el); + $el.empty(); + + if (data === null) { + $el.append(' '); + // clear previous Shiny inputs (if any) + for (var i in instance.clearInputs) instance.clearInputs[i](); + instance.clearInputs = {}; + return; + } + + var crosstalkOptions = data.crosstalkOptions; + if (!crosstalkOptions) crosstalkOptions = { + 'key': null, 'group': null + }; + if (crosstalkOptions.group) { + maybeInstallCrosstalkPlugins(); + instance.ctfilterHandle.setGroup(crosstalkOptions.group); + instance.ctselectHandle.setGroup(crosstalkOptions.group); + } + + // if we are in the viewer then we always want to fillContainer and + // and autoHideNavigation (unless the user has explicitly set these) + if (window.HTMLWidgets.viewerMode) { + if (!data.hasOwnProperty("fillContainer")) + data.fillContainer = true; + if (!data.hasOwnProperty("autoHideNavigation")) + data.autoHideNavigation = true; + } + + // propagate fillContainer to instance (so we have it in resize) + instance.fillContainer = data.fillContainer; + + var cells = data.data; + + if (cells instanceof Array) cells = transposeArray2D(cells); + + $el.append(data.container); + var $table = $el.find('table'); + if (data.class) $table.addClass(data.class); + if (data.caption) $table.prepend(data.caption); + + if (!data.selection) data.selection = { + mode: 'none', selected: null, target: 'row', selectable: null + }; + if (HTMLWidgets.shinyMode && data.selection.mode !== 'none' && + data.selection.target === 'row+column') { + if ($table.children('tfoot').length === 0) { + $table.append($('')); + $table.find('thead tr').clone().appendTo($table.find('tfoot')); + } + } + + // column filters + var filterRow; + switch (data.filter) { + case 'top': + $table.children('thead').append(data.filterHTML); + filterRow = $table.find('thead tr:last td'); + break; + case 'bottom': + if ($table.children('tfoot').length === 0) { + $table.append($('')); + } + $table.children('tfoot').prepend(data.filterHTML); + filterRow = $table.find('tfoot tr:first td'); + break; + } + + var options = { searchDelay: 1000 }; + if (cells !== null) $.extend(options, { + data: cells + }); + + // options for fillContainer + var bootstrapActive = typeof($.fn.popover) != 'undefined'; + if (instance.fillContainer) { + + // force scrollX/scrollY and turn off autoWidth + options.scrollX = true; + options.scrollY = "100px"; // can be any value, we'll adjust below + + // if we aren't paginating then move around the info/filter controls + // to save space at the bottom and rephrase the info callback + if (data.options.paging === false) { + + // we know how to do this cleanly for bootstrap, not so much + // for other themes/layouts + if (bootstrapActive) { + options.dom = "<'row'<'col-sm-4'i><'col-sm-8'f>>" + + "<'row'<'col-sm-12'tr>>"; + } + + options.fnInfoCallback = function(oSettings, iStart, iEnd, + iMax, iTotal, sPre) { + return Number(iTotal).toLocaleString() + " records"; + }; + } + } + + // auto hide navigation if requested + // Note, this only works on client-side processing mode as on server-side, + // cells (data.data) is null; In addition, we require the pageLength option + // being provided explicitly to enable this. Despite we may be able to deduce + // the default value of pageLength, it may complicate things so we'd rather + // put this responsiblity to users and warn them on the R side. + if (data.autoHideNavigation === true && data.options.paging !== false) { + // strip all nav if length >= cells + if ((cells instanceof Array) && data.options.pageLength >= cells.length) + options.dom = bootstrapActive ? "<'row'<'col-sm-12'tr>>" : "t"; + // alternatively lean things out for flexdashboard mobile portrait + else if (bootstrapActive && window.FlexDashboard && window.FlexDashboard.isMobilePhone()) + options.dom = "<'row'<'col-sm-12'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-12'p>>"; + } + + $.extend(true, options, data.options || {}); + + var searchCols = options.searchCols; + if (searchCols) { + searchCols = searchCols.map(function(x) { + return x === null ? '' : x.search; + }); + // FIXME: this means I don't respect the escapeRegex setting + delete options.searchCols; + } + + // server-side processing? + var server = options.serverSide === true; + + // use the dataSrc function to pre-process JSON data returned from R + var DT_rows_all = [], DT_rows_current = []; + if (server && HTMLWidgets.shinyMode && typeof options.ajax === 'object' && + /^session\/[\da-z]+\/dataobj/.test(options.ajax.url) && !options.ajax.dataSrc) { + options.ajax.dataSrc = function(json) { + DT_rows_all = $.makeArray(json.DT_rows_all); + DT_rows_current = $.makeArray(json.DT_rows_current); + var data = json.data; + if (!colReorderEnabled()) return data; + var table = $table.DataTable(), order = table.colReorder.order(), flag = true, i, j, row; + for (i = 0; i < order.length; ++i) if (order[i] !== i) flag = false; + if (flag) return data; + for (i = 0; i < data.length; ++i) { + row = data[i].slice(); + for (j = 0; j < order.length; ++j) data[i][j] = row[order[j]]; + } + return data; + }; + } + + var thiz = this; + if (instance.fillContainer) $table.on('init.dt', function(e) { + thiz.fillAvailableHeight(el, $(el).innerHeight()); + }); + // If the page contains serveral datatables and one of which enables colReorder, + // the table.colReorder.order() function will exist but throws error when called. + // So it seems like the only way to know if colReorder is enabled or not is to + // check the options. + var colReorderEnabled = function() { return "colReorder" in options; }; + var table = $table.DataTable(options); + $el.data('datatable', table); + + if ('rowGroup' in options) { + // Maintain RowGroup dataSrc when columns are reordered (#1109) + table.on('column-reorder', function(e, settings, details) { + var oldDataSrc = table.rowGroup().dataSrc(); + var newDataSrc = details.mapping[oldDataSrc]; + table.rowGroup().dataSrc(newDataSrc); + }); + } + + // Unregister previous Crosstalk event subscriptions, if they exist + if (instance.ctfilterSubscription) { + instance.ctfilterHandle.off("change", instance.ctfilterSubscription); + instance.ctfilterSubscription = null; + } + if (instance.ctselectSubscription) { + instance.ctselectHandle.off("change", instance.ctselectSubscription); + instance.ctselectSubscription = null; + } + + if (!crosstalkOptions.group) { + $table[0].ctfilter = null; + $table[0].ctselect = null; + } else { + var key = crosstalkOptions.key; + function keysToMatches(keys) { + if (!keys) { + return null; + } else { + var selectedKeys = {}; + for (var i = 0; i < keys.length; i++) { + selectedKeys[keys[i]] = true; + } + var matches = {}; + for (var j = 0; j < key.length; j++) { + if (selectedKeys[key[j]]) + matches[j] = true; + } + return matches; + } + } + + function applyCrosstalkFilter(e) { + $table[0].ctfilter = keysToMatches(e.value); + table.draw(); + } + instance.ctfilterSubscription = instance.ctfilterHandle.on("change", applyCrosstalkFilter); + applyCrosstalkFilter({value: instance.ctfilterHandle.filteredKeys}); + + function applyCrosstalkSelection(e) { + if (e.sender !== instance.ctselectHandle) { + table + .rows('.' + selClass, {search: 'applied'}) + .nodes() + .to$() + .removeClass(selClass); + if (selectedRows) + changeInput('rows_selected', selectedRows(), void 0, true); + } + + if (e.sender !== instance.ctselectHandle && e.value && e.value.length) { + var matches = keysToMatches(e.value); + + // persistent selection with plotly (& leaflet) + var ctOpts = crosstalk.var("plotlyCrosstalkOpts").get() || {}; + if (ctOpts.persistent === true) { + var matches = $.extend(matches, $table[0].ctselect); + } + + $table[0].ctselect = matches; + table.draw(); + } else { + if ($table[0].ctselect) { + $table[0].ctselect = null; + table.draw(); + } + } + } + instance.ctselectSubscription = instance.ctselectHandle.on("change", applyCrosstalkSelection); + // TODO: This next line doesn't seem to work when renderDataTable is used + applyCrosstalkSelection({value: instance.ctselectHandle.value}); + } + + var inArray = function(val, array) { + return $.inArray(val, $.makeArray(array)) > -1; + }; + + // search the i-th column + var searchColumn = function(i, value) { + var regex = false, ci = true; + if (options.search) { + regex = options.search.regex, + ci = options.search.caseInsensitive !== false; + } + // need to transpose the column index when colReorder is enabled + if (table.colReorder) i = table.colReorder.transpose(i); + return table.column(i).search(value, regex, !regex, ci); + }; + + if (data.filter !== 'none') { + if (!data.hasOwnProperty('filterSettings')) data.filterSettings = {}; + + filterRow.each(function(i, td) { + + var $td = $(td), type = $td.data('type'), filter; + var $input = $td.children('div').first().children('input'); + var disabled = $input.prop('disabled'); + var searchable = table.settings()[0].aoColumns[i].bSearchable; + $input.prop('disabled', !searchable || disabled); + $input.data('searchable', searchable); // for updating later + $input.on('input blur', function() { + $input.next('span').toggle(Boolean($input.val())); + }); + // Bootstrap sets pointer-events to none and we won't be able to click + // the clear button + $input.next('span').css('pointer-events', 'auto').hide().click(function() { + $(this).hide().prev('input').val('').trigger('input').focus(); + }); + var searchCol; // search string for this column + if (searchCols && searchCols[i]) { + searchCol = searchCols[i]; + $input.val(searchCol).trigger('input'); + } + var $x = $td.children('div').last(); + + // remove the overflow: hidden attribute of the scrollHead + // (otherwise the scrolling table body obscures the filters) + // The workaround and the discussion from + // https://github.com/rstudio/DT/issues/554#issuecomment-518007347 + // Otherwise the filter selection will not be anchored to the values + // when the columns number is many and scrollX is enabled. + var scrollHead = $(el).find('.dataTables_scrollHead,.dataTables_scrollFoot'); + var cssOverflowHead = scrollHead.css('overflow'); + var scrollBody = $(el).find('.dataTables_scrollBody'); + var cssOverflowBody = scrollBody.css('overflow'); + var scrollTable = $(el).find('.dataTables_scroll'); + var cssOverflowTable = scrollTable.css('overflow'); + if (cssOverflowHead === 'hidden') { + $x.on('show hide', function(e) { + if (e.type === 'show') { + scrollHead.css('overflow', 'visible'); + scrollBody.css('overflow', 'visible'); + scrollTable.css('overflow-x', 'scroll'); + } else { + scrollHead.css('overflow', cssOverflowHead); + scrollBody.css('overflow', cssOverflowBody); + scrollTable.css('overflow-x', cssOverflowTable); + } + }); + $x.css('z-index', 25); + } + + if (inArray(type, ['factor', 'logical'])) { + $input.on({ + click: function() { + $input.parent().hide(); $x.show().trigger('show'); filter[0].selectize.focus(); + }, + input: function() { + var v1 = JSON.stringify(filter[0].selectize.getValue()), v2 = $input.val(); + if (v1 === '[]') v1 = ''; + if (v1 !== v2) filter[0].selectize.setValue(v2 === '' ? [] : JSON.parse(v2)); + } + }); + var $input2 = $x.children('select'); + filter = $input2.selectize($.extend({ + options: $input2.data('options').map(function(v, i) { + return ({text: v, value: v}); + }), + plugins: ['remove_button'], + hideSelected: true, + onChange: function(value) { + if (value === null) value = []; // compatibility with jQuery 3.0 + $input.val(value.length ? JSON.stringify(value) : ''); + if (value.length) $input.trigger('input'); + $input.attr('title', $input.val()); + if (server) { + searchColumn(i, value.length ? JSON.stringify(value) : '').draw(); + return; + } + // turn off filter if nothing selected + $td.data('filter', value.length > 0); + table.draw(); // redraw table, and filters will be applied + } + }, data.filterSettings.select)); + filter[0].selectize.on('blur', function() { + $x.hide().trigger('hide'); $input.parent().show(); $input.trigger('blur'); + }); + filter.next('div').css('margin-bottom', 'auto'); + } else if (type === 'character') { + var fun = function() { + searchColumn(i, $input.val()).draw(); + }; + // throttle searching for server-side processing + var throttledFun = $.fn.dataTable.util.throttle(fun, options.searchDelay); + $input.on('input', function(e, immediate) { + // always bypass throttling when immediate = true (via the updateSearch method) + (immediate || !server) ? fun() : throttledFun(); + }); + } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { + var $x0 = $x; + $x = $x0.children('div').first(); + $x0.css({ + 'background-color': '#fff', + 'border': '1px #ddd solid', + 'border-radius': '4px', + 'padding': data.vertical ? '35px 20px': '20px 20px 10px 20px' + }); + var $spans = $x0.children('span').css({ + 'margin-top': data.vertical ? '0' : '10px', + 'white-space': 'nowrap' + }); + var $span1 = $spans.first(), $span2 = $spans.last(); + var r1 = +$x.data('min'), r2 = +$x.data('max'); + // when the numbers are too small or have many decimal places, the + // slider may have numeric precision problems (#150) + var scale = Math.pow(10, Math.max(0, +$x.data('scale') || 0)); + r1 = Math.round(r1 * scale); r2 = Math.round(r2 * scale); + var scaleBack = function(x, scale) { + if (scale === 1) return x; + var d = Math.round(Math.log(scale) / Math.log(10)); + // to avoid problems like 3.423/100 -> 0.034230000000000003 + return (x / scale).toFixed(d); + }; + var slider_min = function() { + return filter.noUiSlider('options').range.min; + }; + var slider_max = function() { + return filter.noUiSlider('options').range.max; + }; + $input.on({ + focus: function() { + $x0.show().trigger('show'); + // first, make sure the slider div leaves at least 20px between + // the two (slider value) span's + $x0.width(Math.max(160, $span1.outerWidth() + $span2.outerWidth() + 20)); + // then, if the input is really wide or slider is vertical, + // make the slider the same width as the input + if ($x0.outerWidth() < $input.outerWidth() || data.vertical) { + $x0.outerWidth($input.outerWidth()); + } + // make sure the slider div does not reach beyond the right margin + if ($(window).width() < $x0.offset().left + $x0.width()) { + $x0.offset({ + 'left': $input.offset().left + $input.outerWidth() - $x0.outerWidth() + }); + } + }, + blur: function() { + $x0.hide().trigger('hide'); + }, + input: function() { + if ($input.val() === '') filter.val([slider_min(), slider_max()]); + }, + change: function() { + var v = $input.val().replace(/\s/g, ''); + if (v === '') return; + v = v.split('...'); + if (v.length !== 2) { + $input.parent().addClass('has-error'); + return; + } + if (v[0] === '') v[0] = slider_min(); + if (v[1] === '') v[1] = slider_max(); + $input.parent().removeClass('has-error'); + // treat date as UTC time at midnight + var strTime = function(x) { + var s = type === 'date' ? 'T00:00:00Z' : ''; + var t = new Date(x + s).getTime(); + // add 10 minutes to date since it does not hurt the date, and + // it helps avoid the tricky floating point arithmetic problems, + // e.g. sometimes the date may be a few milliseconds earlier + // than the midnight due to precision problems in noUiSlider + return type === 'date' ? t + 3600000 : t; + }; + if (inArray(type, ['date', 'time'])) { + v[0] = strTime(v[0]); + v[1] = strTime(v[1]); + } + if (v[0] != slider_min()) v[0] *= scale; + if (v[1] != slider_max()) v[1] *= scale; + filter.val(v); + } + }); + var formatDate = function(d) { + d = scaleBack(d, scale); + if (type === 'number') return d; + if (type === 'integer') return parseInt(d); + var x = new Date(+d); + if (type === 'date') { + var pad0 = function(x) { + return ('0' + x).substr(-2, 2); + }; + return x.getUTCFullYear() + '-' + pad0(1 + x.getUTCMonth()) + + '-' + pad0(x.getUTCDate()); + } else { + return x.toISOString(); + } + }; + var opts = type === 'date' ? { step: 60 * 60 * 1000 } : + type === 'integer' ? { step: 1 } : {}; + + opts.orientation = data.vertical ? 'vertical': 'horizontal'; + opts.direction = data.vertical ? 'rtl': 'ltr'; + + filter = $x.noUiSlider($.extend({ + start: [r1, r2], + range: {min: r1, max: r2}, + connect: true + }, opts, data.filterSettings.slider)); + if (scale > 1) (function() { + var t1 = r1, t2 = r2; + var val = filter.val(); + while (val[0] > r1 || val[1] < r2) { + if (val[0] > r1) { + t1 -= val[0] - r1; + } + if (val[1] < r2) { + t2 += r2 - val[1]; + } + filter = $x.noUiSlider($.extend({ + start: [t1, t2], + range: {min: t1, max: t2}, + connect: true + }, opts, data.filterSettings.slider), true); + val = filter.val(); + } + r1 = t1; r2 = t2; + })(); + // format with active column renderer, if defined + var colDef = data.options.columnDefs.find(function(def) { + return (def.targets === i || inArray(i, def.targets)) && 'render' in def; + }); + var updateSliderText = function(v1, v2) { + // we only know how to use function renderers + if (colDef && typeof colDef.render === 'function') { + var restore = function(v) { + v = scaleBack(v, scale); + return inArray(type, ['date', 'time']) ? new Date(+v) : v; + } + $span1.text(colDef.render(restore(v1), 'display')); + $span2.text(colDef.render(restore(v2), 'display')); + } else { + $span1.text(formatDate(v1)); + $span2.text(formatDate(v2)); + } + }; + updateSliderText(r1, r2); + var updateSlider = function(e) { + var val = filter.val(); + // turn off filter if in full range + $td.data('filter', val[0] > slider_min() || val[1] < slider_max()); + var v1 = formatDate(val[0]), v2 = formatDate(val[1]), ival; + if ($td.data('filter')) { + ival = v1 + ' ... ' + v2; + $input.attr('title', ival).val(ival).trigger('input'); + } else { + $input.attr('title', '').val(''); + } + updateSliderText(val[0], val[1]); + if (e.type === 'slide') return; // no searching when sliding only + if (server) { + searchColumn(i, $td.data('filter') ? ival : '').draw(); + return; + } + table.draw(); + }; + filter.on({ + set: updateSlider, + slide: updateSlider + }); + } + + // server-side processing will be handled by R (or whatever server + // language you use); the following code is only needed for client-side + // processing + if (server) { + // if a search string has been pre-set, search now + if (searchCol) $input.trigger('input').trigger('change'); + return; + } + + var customFilter = function(settings, data, dataIndex) { + // there is no way to attach a search function to a specific table, + // and we need to make sure a global search function is not applied to + // all tables (i.e. a range filter in a previous table should not be + // applied to the current table); we use the settings object to + // determine if we want to perform searching on the current table, + // since settings.sTableId will be different to different tables + if (table.settings()[0] !== settings) return true; + // no filter on this column or no need to filter this column + if (typeof filter === 'undefined' || !$td.data('filter')) return true; + + var r = filter.val(), v, r0, r1; + var i_data = function(i) { + if (!colReorderEnabled()) return i; + var order = table.colReorder.order(), k; + for (k = 0; k < order.length; ++k) if (order[k] === i) return k; + return i; // in theory it will never be here... + } + v = data[i_data(i)]; + if (type === 'number' || type === 'integer') { + v = parseFloat(v); + // how to handle NaN? currently exclude these rows + if (isNaN(v)) return(false); + r0 = parseFloat(scaleBack(r[0], scale)) + r1 = parseFloat(scaleBack(r[1], scale)); + if (v >= r0 && v <= r1) return true; + } else if (type === 'date' || type === 'time') { + v = new Date(v); + r0 = new Date(r[0] / scale); r1 = new Date(r[1] / scale); + if (v >= r0 && v <= r1) return true; + } else if (type === 'factor') { + if (r.length === 0 || inArray(v, r)) return true; + } else if (type === 'logical') { + if (r.length === 0) return true; + if (inArray(v === '' ? 'na' : v, r)) return true; + } + return false; + }; + + $.fn.dataTable.ext.search.push(customFilter); + + // search for the preset search strings if it is non-empty + if (searchCol) $input.trigger('input').trigger('change'); + + }); + + } + + // highlight search keywords + var highlight = function() { + var body = $(table.table().body()); + // removing the old highlighting first + body.unhighlight(); + + // don't highlight the "not found" row, so we get the rows using the api + if (table.rows({ filter: 'applied' }).data().length === 0) return; + // highlight global search keywords + body.highlight($.trim(table.search()).split(/\s+/)); + // then highlight keywords from individual column filters + if (filterRow) filterRow.each(function(i, td) { + var $td = $(td), type = $td.data('type'); + if (type !== 'character') return; + var $input = $td.children('div').first().children('input'); + var column = table.column(i).nodes().to$(), + val = $.trim($input.val()); + if (type !== 'character' || val === '') return; + column.highlight(val.split(/\s+/)); + }); + }; + + if (options.searchHighlight) { + table + .on('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth', highlight) + .on('destroy', function() { + // remove event handler + table.off('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'); + }); + + // Set the option for escaping regex characters in our search string. This will be used + // for all future matching. + jQuery.fn.highlight.options.escapeRegex = (!options.search || !options.search.regex); + + // initial highlight for state saved conditions and initial states + highlight(); + } + + // run the callback function on the table instance + if (typeof data.callback === 'function') data.callback(table); + + // double click to edit the cell, row, column, or all cells + if (data.editable) table.on('dblclick.dt', 'tbody td', function(e) { + // only bring up the editor when the cell itself is dbclicked, and ignore + // other dbclick events bubbled up (e.g. from the ) + if (e.target !== this) return; + var target = [], immediate = false; + switch (data.editable.target) { + case 'cell': + target = [this]; + immediate = true; // edit will take effect immediately + break; + case 'row': + target = table.cells(table.cell(this).index().row, '*').nodes(); + break; + case 'column': + target = table.cells('*', table.cell(this).index().column).nodes(); + break; + case 'all': + target = table.cells().nodes(); + break; + default: + throw 'The editable parameter must be "cell", "row", "column", or "all"'; + } + var disableCols = data.editable.disable ? data.editable.disable.columns : null; + var numericCols = data.editable.numeric; + var areaCols = data.editable.area; + var dateCols = data.editable.date; + for (var i = 0; i < target.length; i++) { + (function(cell, current) { + var $cell = $(cell), html = $cell.html(); + var _cell = table.cell(cell), value = _cell.data(), index = _cell.index().column; + var $input; + if (inArray(index, numericCols)) { + $input = $(''); + } else if (inArray(index, areaCols)) { + $input = $(''); + } else if (inArray(index, dateCols)) { + $input = $(''); + } else { + $input = $(''); + } + if (!immediate) { + $cell.data('input', $input).data('html', html); + $input.attr('title', 'Hit Ctrl+Enter to finish editing, or Esc to cancel'); + } + $input.val(value); + if (inArray(index, disableCols)) { + $input.attr('readonly', '').css('filter', 'invert(25%)'); + } + $cell.empty().append($input); + if (cell === current) $input.focus(); + $input.css('width', '100%'); + + if (immediate) $input.on('blur', function(e) { + var valueNew = $input.val(); + if (valueNew !== value) { + _cell.data(valueNew); + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', [cellInfo(cell)], 'DT.cellInfo', null, {priority: 'event'}); + } + // for server-side processing, users have to call replaceData() to update the table + if (!server) table.draw(false); + } else { + $cell.html(html); + } + }).on('keyup', function(e) { + // hit Escape to cancel editing + if (e.keyCode === 27) $input.trigger('blur'); + }); + + // bulk edit (row, column, or all) + if (!immediate) $input.on('keyup', function(e) { + var removeInput = function($cell, restore) { + $cell.data('input').remove(); + if (restore) $cell.html($cell.data('html')); + } + if (e.keyCode === 27) { + for (var i = 0; i < target.length; i++) { + removeInput($(target[i]), true); + } + } else if (e.keyCode === 13 && e.ctrlKey) { + // Ctrl + Enter + var cell, $cell, _cell, cellData = []; + for (var i = 0; i < target.length; i++) { + cell = target[i]; $cell = $(cell); _cell = table.cell(cell); + _cell.data($cell.data('input').val()); + HTMLWidgets.shinyMode && cellData.push(cellInfo(cell)); + removeInput($cell, false); + } + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', cellData, 'DT.cellInfo', null, {priority: "event"}); + } + if (!server) table.draw(false); + } + }); + })(target[i], this); + } + }); + + // interaction with shiny + if (!HTMLWidgets.shinyMode && !crosstalkOptions.group) return; + + var methods = {}; + var shinyData = {}; + + methods.updateCaption = function(caption) { + if (!caption) return; + $table.children('caption').replaceWith(caption); + } + + // register clear functions to remove input values when the table is removed + instance.clearInputs = {}; + + var changeInput = function(id, value, type, noCrosstalk, opts) { + var event = id; + id = el.id + '_' + id; + if (type) id = id + ':' + type; + // do not update if the new value is the same as old value + if (event !== 'cell_edit' && !/_clicked$/.test(event) && shinyData.hasOwnProperty(id) && shinyData[id] === JSON.stringify(value)) + return; + shinyData[id] = JSON.stringify(value); + if (HTMLWidgets.shinyMode && Shiny.setInputValue) { + Shiny.setInputValue(id, value, opts); + if (!instance.clearInputs[id]) instance.clearInputs[id] = function() { + Shiny.setInputValue(id, null); + } + } + + // HACK + if (event === "rows_selected" && !noCrosstalk) { + if (crosstalkOptions.group) { + var keys = crosstalkOptions.key; + var selectedKeys = null; + if (value) { + selectedKeys = []; + for (var i = 0; i < value.length; i++) { + // The value array's contents use 1-based row numbers, so we must + // convert to 0-based before indexing into the keys array. + selectedKeys.push(keys[value[i] - 1]); + } + } + instance.ctselectHandle.set(selectedKeys); + } + } + }; + + var addOne = function(x) { + return x.map(function(i) { return 1 + i; }); + }; + + var unique = function(x) { + var ux = []; + $.each(x, function(i, el){ + if ($.inArray(el, ux) === -1) ux.push(el); + }); + return ux; + } + + // change the row index of a cell + var tweakCellIndex = function(cell) { + var info = cell.index(); + // some cell may not be valid. e.g, #759 + // when using the RowGroup extension, datatables will + // generate the row label and the cells are not part of + // the data thus contain no row/col info + if (info === undefined) + return {row: null, col: null}; + if (server) { + info.row = DT_rows_current[info.row]; + } else { + info.row += 1; + } + return {row: info.row, col: info.column}; + } + + var cleanSelectedValues = function() { + changeInput('rows_selected', []); + changeInput('columns_selected', []); + changeInput('cells_selected', transposeArray2D([]), 'shiny.matrix'); + } + // #828 we should clean the selection on the server-side when the table reloads + cleanSelectedValues(); + + // a flag to indicates if select extension is initialized or not + var flagSelectExt = table.settings()[0]._select !== undefined; + // the Select extension should only be used in the client mode and + // when the selection.mode is set to none + if (data.selection.mode === 'none' && !server && flagSelectExt) { + var updateRowsSelected = function() { + var rows = table.rows({selected: true}); + var selected = []; + $.each(rows.indexes().toArray(), function(i, v) { + selected.push(v + 1); + }); + changeInput('rows_selected', selected); + } + var updateColsSelected = function() { + var columns = table.columns({selected: true}); + changeInput('columns_selected', columns.indexes().toArray()); + } + var updateCellsSelected = function() { + var cells = table.cells({selected: true}); + var selected = []; + cells.every(function() { + var row = this.index().row; + var col = this.index().column; + selected = selected.concat([[row + 1, col]]); + }); + changeInput('cells_selected', transposeArray2D(selected), 'shiny.matrix'); + } + table.on('select deselect', function(e, dt, type, indexes) { + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + }) + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + } + + var selMode = data.selection.mode, selTarget = data.selection.target; + var selDisable = data.selection.selectable === false; + if (inArray(selMode, ['single', 'multiple'])) { + var selClass = inArray(data.style, ['bootstrap', 'bootstrap4']) ? 'active' : 'selected'; + // selected1: row indices; selected2: column indices + var initSel = function(x) { + if (x === null || typeof x === 'boolean' || selTarget === 'cell') { + return {rows: [], cols: []}; + } else if (selTarget === 'row') { + return {rows: $.makeArray(x), cols: []}; + } else if (selTarget === 'column') { + return {rows: [], cols: $.makeArray(x)}; + } else if (selTarget === 'row+column') { + return {rows: $.makeArray(x.rows), cols: $.makeArray(x.cols)}; + } + } + var selected = data.selection.selected; + var selected1 = initSel(selected).rows, selected2 = initSel(selected).cols; + // selectable should contain either all positive or all non-positive values, not both + // positive values indicate "selectable" while non-positive values means "nonselectable" + // the assertion is performed on R side. (only column indicides could be zero which indicates + // the row name) + var selectable = data.selection.selectable; + var selectable1 = initSel(selectable).rows, selectable2 = initSel(selectable).cols; + + // After users reorder the rows or filter the table, we cannot use the table index + // directly. Instead, we need this function to find out the rows between the two clicks. + // If user filter the table again between the start click and the end click, the behavior + // would be undefined, but it should not be a problem. + var shiftSelRowsIndex = function(start, end) { + var indexes = server ? DT_rows_all : table.rows({ search: 'applied' }).indexes().toArray(); + start = indexes.indexOf(start); end = indexes.indexOf(end); + // if start is larger than end, we need to swap + if (start > end) { + var tmp = end; end = start; start = tmp; + } + return indexes.slice(start, end + 1); + } + + var serverRowIndex = function(clientRowIndex) { + return server ? DT_rows_current[clientRowIndex] : clientRowIndex + 1; + } + + // row, column, or cell selection + var lastClickedRow; + if (inArray(selTarget, ['row', 'row+column'])) { + // Get the current selected rows. It will also + // update the selected1's value based on the current row selection state + // Note we can't put this function inside selectRows() directly, + // the reason is method.selectRows() will override selected1's value but this + // function will add rows to selected1 (keep the existing selection), which is + // inconsistent with column and cell selection. + var selectedRows = function() { + var rows = table.rows('.' + selClass); + var idx = rows.indexes().toArray(); + if (!server) { + selected1 = addOne(idx); + return selected1; + } + idx = idx.map(function(i) { + return DT_rows_current[i]; + }); + selected1 = selMode === 'multiple' ? unique(selected1.concat(idx)) : idx; + return selected1; + } + // Change selected1's value based on selectable1, then refresh the row state + var onlyKeepSelectableRows = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected1 = []; + return; + } + if (selectable1.length === 0) return; + var nonselectable = selectable1[0] <= 0; + if (nonselectable) { + // should make selectable1 positive + selected1 = $(selected1).not(selectable1.map(function(i) { return -i; })).get(); + } else { + selected1 = $(selected1).filter(selectable1).get(); + } + } + // Change selected1's value based on selectable1, then + // refresh the row selection state according to values in selected1 + var selectRows = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableRows(); + table.$('tr.' + selClass).removeClass(selClass); + if (selected1.length === 0) return; + if (server) { + table.rows({page: 'current'}).every(function() { + if (inArray(DT_rows_current[this.index()], selected1)) { + $(this.node()).addClass(selClass); + } + }); + } else { + var selected0 = selected1.map(function(i) { return i - 1; }); + $(table.rows(selected0).nodes()).addClass(selClass); + } + } + table.on('mousedown.dt', 'tbody tr', function(e) { + var $this = $(this), thisRow = table.row(this); + if (selMode === 'multiple') { + if (e.shiftKey && lastClickedRow !== undefined) { + // select or de-select depends on the last clicked row's status + var flagSel = !$this.hasClass(selClass); + var crtClickedRow = serverRowIndex(thisRow.index()); + if (server) { + var rowsIndex = shiftSelRowsIndex(lastClickedRow, crtClickedRow); + // update current page's selClass + rowsIndex.map(function(i) { + var rowIndex = DT_rows_current.indexOf(i); + if (rowIndex >= 0) { + var row = table.row(rowIndex).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + } + }); + // update selected1 + if (flagSel) { + selected1 = unique(selected1.concat(rowsIndex)); + } else { + selected1 = selected1.filter(function(index) { + return !inArray(index, rowsIndex); + }); + } + } else { + // js starts from 0 + shiftSelRowsIndex(lastClickedRow - 1, crtClickedRow - 1).map(function(value) { + var row = table.row(value).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + }); + } + e.preventDefault(); + } else { + $this.toggleClass(selClass); + } + } else { + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + } else { + table.$('tr.' + selClass).removeClass(selClass); + $this.addClass(selClass); + } + } + if (server && !$this.hasClass(selClass)) { + var id = DT_rows_current[thisRow.index()]; + // remove id from selected1 since its class .selected has been removed + if (inArray(id, selected1)) selected1.splice($.inArray(id, selected1), 1); + } + selectedRows(); // update selected1's value based on selClass + selectRows(false); // only keep the selectable rows + changeInput('rows_selected', selected1); + changeInput('row_last_clicked', serverRowIndex(thisRow.index()), null, null, {priority: 'event'}); + lastClickedRow = serverRowIndex(thisRow.index()); + }); + selectRows(false); // in case users have specified pre-selected rows + // restore selected rows after the table is redrawn (e.g. sort/search/page); + // client-side tables will preserve the selections automatically; for + // server-side tables, we have to *real* row indices are in `selected1` + changeInput('rows_selected', selected1); + if (server) table.on('draw.dt', function(e) { selectRows(false); }); + methods.selectRows = function(selected, ignoreSelectable) { + selected1 = $.makeArray(selected); + selectRows(ignoreSelectable); + changeInput('rows_selected', selected1); + } + } + + if (inArray(selTarget, ['column', 'row+column'])) { + if (selTarget === 'row+column') { + $(table.columns().footer()).css('cursor', 'pointer'); + } + // update selected2's value based on selectable2 + var onlyKeepSelectableCols = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected2 = []; + return; + } + if (selectable2.length === 0) return; + var nonselectable = selectable2[0] <= 0; + if (nonselectable) { + // need to make selectable2 positive + selected2 = $(selected2).not(selectable2.map(function(i) { return -i; })).get(); + } else { + selected2 = $(selected2).filter(selectable2).get(); + } + } + // update selected2 and then + // refresh the col selection state according to values in selected2 + var selectCols = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCols(); + // if selected2 is not a valide index (e.g., larger than the column number) + // table.columns(selected2) will fail and result in a blank table + // this is different from the table.rows(), where the out-of-range indexes + // doesn't affect at all + selected2 = $(selected2).filter(table.columns().indexes()).get(); + table.columns().nodes().flatten().to$().removeClass(selClass); + if (selected2.length > 0) + table.columns(selected2).nodes().flatten().to$().addClass(selClass); + } + var callback = function() { + var colIdx = selTarget === 'column' ? table.cell(this).index().column : + $.inArray(this, table.columns().footer()), + thisCol = $(table.column(colIdx).nodes()); + if (colIdx === -1) return; + if (thisCol.hasClass(selClass)) { + thisCol.removeClass(selClass); + selected2.splice($.inArray(colIdx, selected2), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + thisCol.addClass(selClass); + selected2 = selMode === 'single' ? [colIdx] : unique(selected2.concat([colIdx])); + } + selectCols(false); // update selected2 based on selectable + changeInput('columns_selected', selected2); + } + if (selTarget === 'column') { + $(table.table().body()).on('click.dt', 'td', callback); + } else { + $(table.table().footer()).on('click.dt', 'tr th', callback); + } + selectCols(false); // in case users have specified pre-selected columns + changeInput('columns_selected', selected2); + if (server) table.on('draw.dt', function(e) { selectCols(false); }); + methods.selectColumns = function(selected, ignoreSelectable) { + selected2 = $.makeArray(selected); + selectCols(ignoreSelectable); + changeInput('columns_selected', selected2); + } + } + + if (selTarget === 'cell') { + var selected3 = [], selectable3 = []; + if (selected !== null) selected3 = selected; + if (selectable !== null && typeof selectable !== 'boolean') selectable3 = selectable; + var findIndex = function(ij, sel) { + for (var i = 0; i < sel.length; i++) { + if (ij[0] === sel[i][0] && ij[1] === sel[i][1]) return i; + } + return -1; + } + // Change selected3's value based on selectable3, then refresh the cell state + var onlyKeepSelectableCells = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected3 = []; + return; + } + if (selectable3.length === 0) return; + var nonselectable = selectable3[0][0] <= 0; + var out = []; + if (nonselectable) { + selected3.map(function(ij) { + // should make selectable3 positive + if (findIndex([-ij[0], -ij[1]], selectable3) === -1) { out.push(ij); } + }); + } else { + selected3.map(function(ij) { + if (findIndex(ij, selectable3) > -1) { out.push(ij); } + }); + } + selected3 = out; + } + // Change selected3's value based on selectable3, then + // refresh the cell selection state according to values in selected3 + var selectCells = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCells(); + table.$('td.' + selClass).removeClass(selClass); + if (selected3.length === 0) return; + if (server) { + table.cells({page: 'current'}).every(function() { + var info = tweakCellIndex(this); + if (findIndex([info.row, info.col], selected3) > -1) + $(this.node()).addClass(selClass); + }); + } else { + selected3.map(function(ij) { + $(table.cell(ij[0] - 1, ij[1]).node()).addClass(selClass); + }); + } + }; + table.on('click.dt', 'tbody td', function() { + var $this = $(this), info = tweakCellIndex(table.cell(this)); + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + selected3.splice(findIndex([info.row, info.col], selected3), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + $this.addClass(selClass); + selected3 = selMode === 'single' ? [[info.row, info.col]] : + unique(selected3.concat([[info.row, info.col]])); + } + selectCells(false); // must call this to update selected3 based on selectable3 + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + }); + selectCells(false); // in case users have specified pre-selected columns + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + + if (server) table.on('draw.dt', function(e) { selectCells(false); }); + methods.selectCells = function(selected, ignoreSelectable) { + selected3 = selected ? selected : []; + selectCells(ignoreSelectable); + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + } + } + } + + // expose some table info to Shiny + var updateTableInfo = function(e, settings) { + // TODO: is anyone interested in the page info? + // changeInput('page_info', table.page.info()); + var updateRowInfo = function(id, modifier) { + var idx; + if (server) { + idx = modifier.page === 'current' ? DT_rows_current : DT_rows_all; + } else { + var rows = table.rows($.extend({ + search: 'applied', + page: 'all' + }, modifier)); + idx = addOne(rows.indexes().toArray()); + } + changeInput('rows' + '_' + id, idx); + }; + updateRowInfo('current', {page: 'current'}); + updateRowInfo('all', {}); + } + table.on('draw.dt', updateTableInfo); + updateTableInfo(); + + // state info + table.on('draw.dt column-visibility.dt', function() { + changeInput('state', table.state()); + }); + changeInput('state', table.state()); + + // search info + var updateSearchInfo = function() { + changeInput('search', table.search()); + if (filterRow) changeInput('search_columns', filterRow.toArray().map(function(td) { + return $(td).find('input').first().val(); + })); + } + table.on('draw.dt', updateSearchInfo); + updateSearchInfo(); + + var cellInfo = function(thiz) { + var info = tweakCellIndex(table.cell(thiz)); + info.value = table.cell(thiz).data(); + return info; + } + // the current cell clicked on + table.on('click.dt', 'tbody td', function() { + changeInput('cell_clicked', cellInfo(this), null, null, {priority: 'event'}); + }) + changeInput('cell_clicked', {}); + + // do not trigger table selection when clicking on links unless they have classes + table.on('mousedown.dt', 'tbody td a', function(e) { + if (this.className === '') e.stopPropagation(); + }); + + methods.addRow = function(data, rowname, resetPaging) { + var n = table.columns().indexes().length, d = n - data.length; + if (d === 1) { + data = rowname.concat(data) + } else if (d !== 0) { + console.log(data); + console.log(table.columns().indexes()); + throw 'New data must be of the same length as current data (' + n + ')'; + }; + table.row.add(data).draw(resetPaging); + } + + methods.updateSearch = function(keywords) { + if (keywords.global !== null) + $(table.table().container()).find('input[type=search]').first() + .val(keywords.global).trigger('input'); + var columns = keywords.columns; + if (!filterRow || columns === null) return; + filterRow.toArray().map(function(td, i) { + var v = typeof columns === 'string' ? columns : columns[i]; + if (typeof v === 'undefined') { + console.log('The search keyword for column ' + i + ' is undefined') + return; + } + // Update column search string and values on linked filter widgets. + // 'input' for factor and char filters, 'change' for numeric filters. + $(td).find('input').first().val(v).trigger('input', [true]).trigger('change'); + }); + table.draw(); + } + + methods.hideCols = function(hide, reset) { + if (reset) table.columns().visible(true, false); + table.columns(hide).visible(false); + } + + methods.showCols = function(show, reset) { + if (reset) table.columns().visible(false, false); + table.columns(show).visible(true); + } + + methods.colReorder = function(order, origOrder) { + table.colReorder.order(order, origOrder); + } + + methods.selectPage = function(page) { + if (table.page.info().pages < page || page < 1) { + throw 'Selected page is out of range'; + }; + table.page(page - 1).draw(false); + } + + methods.reloadData = function(resetPaging, clearSelection) { + // empty selections first if necessary + if (methods.selectRows && inArray('row', clearSelection)) methods.selectRows([]); + if (methods.selectColumns && inArray('column', clearSelection)) methods.selectColumns([]); + if (methods.selectCells && inArray('cell', clearSelection)) methods.selectCells([]); + table.ajax.reload(null, resetPaging); + } + + // update table filters (set new limits of sliders) + methods.updateFilters = function(newProps) { + // loop through each filter in the filter row + filterRow.each(function(i, td) { + var k = i; + if (filterRow.length > newProps.length) { + if (i === 0) return; // first column is row names + k = i - 1; + } + // Update the filters to reflect the updated data. + // Allow "falsy" (e.g. NULL) to signify a no-op. + if (newProps[k]) { + setFilterProps(td, newProps[k]); + } + }); + }; + + table.shinyMethods = methods; + }, + resize: function(el, width, height, instance) { + if (instance.data) this.renderValue(el, instance.data, instance); + + // dynamically adjust height if fillContainer = TRUE + if (instance.fillContainer) + this.fillAvailableHeight(el, height); + + this.adjustWidth(el); + }, + + // dynamically set the scroll body to fill available height + // (used with fillContainer = TRUE) + fillAvailableHeight: function(el, availableHeight) { + + // see how much of the table is occupied by header/footer elements + // and use that to compute a target scroll body height + var dtWrapper = $(el).find('div.dataTables_wrapper'); + var dtScrollBody = $(el).find($('div.dataTables_scrollBody')); + var framingHeight = dtWrapper.innerHeight() - dtScrollBody.innerHeight(); + var scrollBodyHeight = availableHeight - framingHeight; + + // we need to set `max-height` to none as datatables library now sets this + // to a fixed height, disabling the ability to resize to fill the window, + // as it will be set to a fixed 100px under such circumstances, e.g., RStudio IDE, + // or FlexDashboard + // see https://github.com/rstudio/DT/issues/951#issuecomment-1026464509 + dtScrollBody.css('max-height', 'none'); + // set the height + dtScrollBody.height(scrollBodyHeight + 'px'); + }, + + // adjust the width of columns; remove the hard-coded widths on table and the + // scroll header when scrollX/Y are enabled + adjustWidth: function(el) { + var $el = $(el), table = $el.data('datatable'); + if (table) table.columns.adjust(); + $el.find('.dataTables_scrollHeadInner').css('width', '') + .children('table').css('margin-left', ''); + } +}); + + if (!HTMLWidgets.shinyMode) return; + + Shiny.addCustomMessageHandler('datatable-calls', function(data) { + var id = data.id; + var el = document.getElementById(id); + var table = el ? $(el).data('datatable') : null; + if (!table) { + console.log("Couldn't find table with id " + id); + return; + } + + var methods = table.shinyMethods, call = data.call; + if (methods[call.method]) { + methods[call.method].apply(table, call.args); + } else { + console.log("Unknown method " + call.method); + } + }); + +})(); diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-css/datatables-crosstalk.css b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-css/datatables-crosstalk.css new file mode 100644 index 0000000..bd1159c --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-css/datatables-crosstalk.css @@ -0,0 +1,32 @@ +.dt-crosstalk-fade { + opacity: 0.2; +} + +html body div.DTS div.dataTables_scrollBody { + background: none; +} + + +/* +Fix https://github.com/rstudio/DT/issues/563 +If the `table.display` is set to "block" (e.g., pkgdown), the browser will display +datatable objects strangely. The search panel and the page buttons will still be +in full-width but the table body will be "compact" and shorter. +In therory, having this attributes will affect `dom="t"` +with `display: block` users. But in reality, there should be no one. +We may remove the below lines in the future if the upstream agree to have this there. +See https://github.com/DataTables/DataTablesSrc/issues/160 +*/ + +table.dataTable { + display: table; +} + + +/* +When DTOutput(fill = TRUE), it receives a .html-fill-item class (via htmltools::bindFillRole()), which effectively amounts to `flex: 1 1 auto`. That's mostly fine, but the case where `fillContainer=TRUE`+`height:auto`+`flex-basis:auto` and the container (e.g., a bslib::card()) doesn't have a defined height is a bit problematic since the table wants to fit the parent but the parent wants to fit the table, which results pretty small table height (maybe because there is a minimum height somewhere?). It seems better in this case to impose a 400px height default for the table, which we can do by setting `flex-basis` to 400px (the table is still allowed to grow/shrink when the container has an opinionated height). +*/ + +.html-fill-container > .html-fill-item.datatables { + flex-basis: 400px; +} diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.extra.css b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.extra.css new file mode 100644 index 0000000..b2dd141 --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.extra.css @@ -0,0 +1,28 @@ +/* Selected rows/cells */ +table.dataTable tr.selected td, table.dataTable td.selected { + background-color: #b0bed9 !important; +} +/* In case of scrollX/Y or FixedHeader */ +.dataTables_scrollBody .dataTables_sizing { + visibility: hidden; +} + +/* The datatables' theme CSS file doesn't define +the color but with white background. It leads to an issue that +when the HTML's body color is set to 'white', the user can't +see the text since the background is white. One case happens in the +RStudio's IDE when inline viewing the DT table inside an Rmd file, +if the IDE theme is set to "Cobalt". + +See https://github.com/rstudio/DT/issues/447 for more info + +This fixes should have little side-effects because all the other elements +of the default theme use the #333 font color. + +TODO: The upstream may use relative colors for both the table background +and the color. It means the table can display well without this patch +then. At that time, we need to remove the below CSS attributes. +*/ +div.datatables { + color: #333; +} diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.min.css b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.min.css new file mode 100644 index 0000000..ad59f84 --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.min.css @@ -0,0 +1 @@ +:root{--dt-row-selected: 13, 110, 253;--dt-row-selected-text: 255, 255, 255;--dt-row-selected-link: 9, 10, 11;--dt-row-stripe: 0, 0, 0;--dt-row-hover: 0, 0, 0;--dt-column-ordering: 0, 0, 0;--dt-html-background: white}:root.dark{--dt-html-background: rgb(33, 37, 41)}table.dataTable td.dt-control{text-align:center;cursor:pointer}table.dataTable td.dt-control:before{display:inline-block;color:rgba(0, 0, 0, 0.5);content:"►"}table.dataTable tr.dt-hasChild td.dt-control:before{content:"▼"}html.dark table.dataTable td.dt-control:before{color:rgba(255, 255, 255, 0.5)}html.dark table.dataTable tr.dt-hasChild td.dt-control:before{color:rgba(255, 255, 255, 0.5)}table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting_asc_disabled,table.dataTable thead>tr>th.sorting_desc_disabled,table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting_asc_disabled,table.dataTable thead>tr>td.sorting_desc_disabled{cursor:pointer;position:relative;padding-right:26px}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after{position:absolute;display:block;opacity:.125;right:10px;line-height:9px;font-size:.8em}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:before{bottom:50%;content:"▲";content:"▲"/""}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:after{top:50%;content:"▼";content:"▼"/""}table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:after{opacity:.6}table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting_asc_disabled:before{display:none}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}div.dataTables_scrollBody>table.dataTable>thead>tr>th:before,div.dataTables_scrollBody>table.dataTable>thead>tr>th:after,div.dataTables_scrollBody>table.dataTable>thead>tr>td:before,div.dataTables_scrollBody>table.dataTable>thead>tr>td:after{display:none}div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:2px}div.dataTables_processing>div:last-child{position:relative;width:80px;height:15px;margin:1em auto}div.dataTables_processing>div:last-child>div{position:absolute;top:0;width:13px;height:13px;border-radius:50%;background:rgb(13, 110, 253);background:rgb(var(--dt-row-selected));animation-timing-function:cubic-bezier(0, 1, 1, 0)}div.dataTables_processing>div:last-child>div:nth-child(1){left:8px;animation:datatables-loader-1 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(2){left:8px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(3){left:32px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(4){left:56px;animation:datatables-loader-3 .6s infinite}@keyframes datatables-loader-1{0%{transform:scale(0)}100%{transform:scale(1)}}@keyframes datatables-loader-3{0%{transform:scale(1)}100%{transform:scale(0)}}@keyframes datatables-loader-2{0%{transform:translate(0, 0)}100%{transform:translate(24px, 0)}}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th,table.dataTable thead td,table.dataTable tfoot th,table.dataTable tfoot td{text-align:left}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable>thead>tr>th,table.dataTable>thead>tr>td{padding:10px;border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable>thead>tr>th:active,table.dataTable>thead>tr>td:active{outline:none}table.dataTable>tfoot>tr>th,table.dataTable>tfoot>tr>td{padding:10px 10px 6px 10px;border-top:1px solid rgba(0, 0, 0, 0.3)}table.dataTable tbody tr{background-color:transparent}table.dataTable tbody tr.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.9);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.9);color:rgb(255, 255, 255);color:rgb(var(--dt-row-selected-text))}table.dataTable tbody tr.selected a{color:rgb(9, 10, 11);color:rgb(var(--dt-row-selected-link))}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border>tbody>tr>th,table.dataTable.row-border>tbody>tr>td,table.dataTable.display>tbody>tr>th,table.dataTable.display>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.row-border>tbody>tr:first-child>th,table.dataTable.row-border>tbody>tr:first-child>td,table.dataTable.display>tbody>tr:first-child>th,table.dataTable.display>tbody>tr:first-child>td{border-top:none}table.dataTable.row-border>tbody>tr.selected+tr.selected>td,table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0262ef}table.dataTable.cell-border>tbody>tr>th,table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15);border-right:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr>th:first-child,table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr:first-child>th,table.dataTable.cell-border>tbody>tr:first-child>td{border-top:none}table.dataTable.stripe>tbody>tr.odd>*,table.dataTable.display>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.023);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.023)}table.dataTable.stripe>tbody>tr.odd.selected>*,table.dataTable.display>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.923);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.923)}table.dataTable.hover>tbody>tr:hover>*,table.dataTable.display>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.035);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.035)}table.dataTable.hover>tbody>tr.selected:hover>*,table.dataTable.display>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px #0d6efd !important;box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 1) !important}table.dataTable.order-column>tbody tr>.sorting_1,table.dataTable.order-column>tbody tr>.sorting_2,table.dataTable.order-column>tbody tr>.sorting_3,table.dataTable.display>tbody tr>.sorting_1,table.dataTable.display>tbody tr>.sorting_2,table.dataTable.display>tbody tr>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.019)}table.dataTable.order-column>tbody tr.selected>.sorting_1,table.dataTable.order-column>tbody tr.selected>.sorting_2,table.dataTable.order-column>tbody tr.selected>.sorting_3,table.dataTable.display>tbody tr.selected>.sorting_1,table.dataTable.display>tbody tr.selected>.sorting_2,table.dataTable.display>tbody tr.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.odd>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.054);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.054)}table.dataTable.display>tbody>tr.odd>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.047);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.047)}table.dataTable.display>tbody>tr.odd>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.039);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.039)}table.dataTable.display>tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.954);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.954)}table.dataTable.display>tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.947);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.947)}table.dataTable.display>tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.939);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.939)}table.dataTable.display>tbody>tr.even>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.019)}table.dataTable.display>tbody>tr.even>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.011);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.011)}table.dataTable.display>tbody>tr.even>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.003);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.003)}table.dataTable.display>tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.911);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.911)}table.dataTable.display>tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.903);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.903)}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.082);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.082)}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.074);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.074)}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.062);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.062)}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.982);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.982)}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.974);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.974)}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.962);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.962)}table.dataTable.no-footer{border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable.compact thead th,table.dataTable.compact thead td,table.dataTable.compact tfoot th,table.dataTable.compact tfoot td,table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_length select{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;padding:4px}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;margin-left:3px}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;color:inherit !important;border:1px solid transparent;border-radius:2px;background:transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:inherit !important;border:1px solid rgba(0, 0, 0, 0.3);background-color:rgba(0, 0, 0, 0.05);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.05)), color-stop(100%, rgba(0, 0, 0, 0.05)));background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#111;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#0c0c0c;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:inherit}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid rgba(0, 0, 0, 0.3)}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}}html.dark{--dt-row-hover: 255, 255, 255;--dt-row-stripe: 255, 255, 255;--dt-column-ordering: 255, 255, 255}html.dark table.dataTable>thead>tr>th,html.dark table.dataTable>thead>tr>td{border-bottom:1px solid rgb(89, 91, 94)}html.dark table.dataTable>thead>tr>th:active,html.dark table.dataTable>thead>tr>td:active{outline:none}html.dark table.dataTable>tfoot>tr>th,html.dark table.dataTable>tfoot>tr>td{border-top:1px solid rgb(89, 91, 94)}html.dark table.dataTable.row-border>tbody>tr>th,html.dark table.dataTable.row-border>tbody>tr>td,html.dark table.dataTable.display>tbody>tr>th,html.dark table.dataTable.display>tbody>tr>td{border-top:1px solid rgb(64, 67, 70)}html.dark table.dataTable.row-border>tbody>tr.selected+tr.selected>td,html.dark table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0257d5}html.dark table.dataTable.cell-border>tbody>tr>th,html.dark table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgb(64, 67, 70);border-right:1px solid rgb(64, 67, 70)}html.dark table.dataTable.cell-border>tbody>tr>th:first-child,html.dark table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgb(64, 67, 70)}html.dark .dataTables_wrapper .dataTables_filter input,html.dark .dataTables_wrapper .dataTables_length select{border:1px solid rgba(255, 255, 255, 0.2);background-color:var(--dt-html-background)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{border:1px solid rgb(89, 91, 94);background:rgba(255, 255, 255, 0.15)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{color:#666 !important}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:hover{border:1px solid rgb(53, 53, 53);background:rgb(53, 53, 53)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:active{background:#3a3a3a} diff --git a/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/js/jquery.dataTables.min.js b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/js/jquery.dataTables.min.js new file mode 100644 index 0000000..f786b0d --- /dev/null +++ b/content/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/js/jquery.dataTables.min.js @@ -0,0 +1,4 @@ +/*! DataTables 1.13.6 + * ©2008-2023 SpryMedia Ltd - datatables.net/license + */ +!function(n){"use strict";var a;"function"==typeof define&&define.amd?define(["jquery"],function(t){return n(t,window,document)}):"object"==typeof exports?(a=require("jquery"),"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||a(t),n(e,t,t.document)}:n(a,window,window.document)):window.DataTable=n(jQuery,window,document)}(function(P,j,v,H){"use strict";function d(t){var e=parseInt(t,10);return!isNaN(e)&&isFinite(t)?e:null}function l(t,e,n){var a=typeof t,r="string"==a;return"number"==a||"bigint"==a||!!h(t)||(e&&r&&(t=$(t,e)),n&&r&&(t=t.replace(q,"")),!isNaN(parseFloat(t))&&isFinite(t))}function a(t,e,n){var a;return!!h(t)||(h(a=t)||"string"==typeof a)&&!!l(t.replace(V,"").replace(/ + \ No newline at end of file diff --git a/layouts/shortcodes/blogdown/postref.html b/layouts/shortcodes/blogdown/postref.html new file mode 100644 index 0000000..858ad3e --- /dev/null +++ b/layouts/shortcodes/blogdown/postref.html @@ -0,0 +1 @@ +{{ if eq (getenv "HUGO_BLOGDOWN_POST_RELREF") "true" }}{{ .Page.RelPermalink }}{{ else }}{{ .Page.Permalink }}{{ end }} \ No newline at end of file diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..941e700 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,17 @@ +[build] +command = 'hugo' +publish = 'public' + +[build.environment] +HUGO_VERSION = '0.128.2' + +[context] +[context.branch-deploy] +command = 'hugo -F -b $DEPLOY_PRIME_URL' + +[context.deploy-preview] +command = 'hugo -F -b $DEPLOY_PRIME_URL' + +[context.production] +[context.production.environment] +HUGO_ENV = 'production' diff --git a/public/2018/03/18/fearlessness-how-to-stop-running-from-space/index.html b/public/2018/03/18/fearlessness-how-to-stop-running-from-space/index.html new file mode 100644 index 0000000..c9af7b9 --- /dev/null +++ b/public/2018/03/18/fearlessness-how-to-stop-running-from-space/index.html @@ -0,0 +1,159 @@ + + + + Fearlessness: How to Stop Running from Space - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Fearlessness: How to Stop Running from Space

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos.

+

We are afraid of empty space in our lives.

+

The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives.

+

We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. We try to fill every second with activity, with something useful, as if silence and space are not valuable.

+

But what are we afraid of?

+

And who would we be if we didn’t have that fear?

+

We’re afraid of space and stillness and silence because it highlights the uncertainty, instability, groundlessness, insecurity, shakiness that lie underneath every second of our lives. We’re afraid of having to face this instability and uncertainty, of having to feel the fear of it.

+

Without the fear of all of the uncertainty that is highlighted by space … we become free.

+

I know in my life, when I allow myself to have stillness, silence, solitude, simplicity and space … it leaves room to face whatever is coming up for me. It gives me room to fully feel any feelings that I’ve been avoiding. It allows me to be more honest with myself, instead of using distractions and busyness to cover up what I don’t want to see.

+

And in the end, I develop trust that the space is not something to be feared, but rather something to be treasured. A gift, filled with learning and not knowing and shakiness and beauty.

+

You might try allowing more space to be in your day, without filling it:

+
    +
  • Take some time between tasks for stillness.
  • +
  • Sit out in nature, in silence, without technology.
  • +
  • When you notice yourself reaching for your phone, pause. See if you can just be still, just savor some space.
  • +
  • When you feel uncertainty or instability in your life (hint: it’s always there), let yourself feel it. Be present with it, without needing to run or avoid.
  • +
  • When you feel fear, be open-hearted with it and allow yourself fully feel it, being friendly with it. Your relationship with fear will change if you become friendly with it.
  • +
  • Do less, and trust that things won’t fall apart. Or if they do fall apart, you can be present with that instability.
  • +
  • When you’re in line, driving, eating, walking, exercising … see if you can do those things in silence, without technology, without needing to do something “useful.” Find the value in these spaces.
  • +
  • Notice who you are without the fear of space.
  • +
+

Savor these spaces, their deliciousness. Savor the groundlessness, as something filled with freedom if we learn not to fear it. Be present with the fear and uncertainty, as good friends not as enemies.

+

Let your heart be open raw tender and vulnerable, and your mind embracing the spaciousness of the vast blue sky of open awareness.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2018/03/18/how-i-learned-to-stop-procrastinating-love-letting-go/index.html b/public/2018/03/18/how-i-learned-to-stop-procrastinating-love-letting-go/index.html new file mode 100644 index 0000000..0dbbfa7 --- /dev/null +++ b/public/2018/03/18/how-i-learned-to-stop-procrastinating-love-letting-go/index.html @@ -0,0 +1,145 @@ + + + + How I Learned to Stop Procrastinating, & Love Letting Go - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

How I Learned to Stop Procrastinating, & Love Letting Go

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

The end of procrastination is the art of letting go.

+

I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done.

+

Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. It stressed me out. My work was less-than-desirable when I did it last minute. Slowly, I started to realize that procrastination wasn’t doing me any favors. In fact, it was causing me a lot of grief.

+

But I couldn’t quit. I tried a lot of things. I tried time boxing and goal setting and accountability and the Pomodoro Technique and Getting Things Done. All are great methods, but they only last so long. Nothing really worked over the long term.

+

That’s because I wasn’t getting to the root problem.

+

I hadn’t figured out the skill that would save me from the procrastination.

+

Until I learned about letting go.

+

Letting go first came to me when I was quitting smoking. I had to let go of the “need” to smoke, the use of my crutch of cigarettes to deal with stress and problems.

+

Then I learned I needed to let go of other false needs that were causing me problems: sugar, junk food, meat, shopping, beer, possessions. I’m not saying I can never do these things again once I let go of these needs, but I let go of the idea that they’re really necessary. I let go of an unhealthy attachment to them.

+

Then I learned that distractions and the false need to check my email and news and other things online … were causing me problems. They were causing my procrastination.

+

So I learned to let go of those too.

+

Here’s the process I used to let go of the distractions and false needs that cause procrastination:

+

I paid attention to the pain they cause me, later, instead of only the temporary comfort/pleasure they gave me right away. +I thought about the person I want to be, the life I want to live. I set my intentions to do the good work I think I should do. +I watched my urges to check things, to go to the comfort of distractions. I saw that I wanted to escape discomfort of something hard, and go to the comfort of something familiar and easy. +I realized I didn’t need that comfort. I could be in discomfort and nothing bad would happen. In fact, the best things happen when I’m in discomfort. +And then I smile, and breathe, and let go.

+

And one step at a time, become the person I want to be.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2018/03/18/how-to-test-dark-mode/index.html b/public/2018/03/18/how-to-test-dark-mode/index.html new file mode 100644 index 0000000..eb7bae2 --- /dev/null +++ b/public/2018/03/18/how-to-test-dark-mode/index.html @@ -0,0 +1,129 @@ + + + + How to test dark mode? - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

How to test dark mode?

+
Posted on Mar 18, 2018 DRAFT
+
+ +
+ tl;dr: + Wubba lubba dub dub +
+ +
+ +

Table of Contents

+ + +
+ +
+

You can set dark mode as default by setting params.mode to dark in config.toml or set it to auto which will detect based on your OS and switch to dark mode. For more details refer documentation

+

Here is how you can switch based on your OS

+ + +
+ + + + +
+
+ +
+ + diff --git a/public/2018/03/18/hugo-shortcodes/index.html b/public/2018/03/18/hugo-shortcodes/index.html new file mode 100644 index 0000000..06c4f97 --- /dev/null +++ b/public/2018/03/18/hugo-shortcodes/index.html @@ -0,0 +1,385 @@ + + + + Hugo shortcodes - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+ +
+ +
+ + diff --git a/public/2018/03/18/typography/index.html b/public/2018/03/18/typography/index.html new file mode 100644 index 0000000..d118a04 --- /dev/null +++ b/public/2018/03/18/typography/index.html @@ -0,0 +1,181 @@ + + + + Typography - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Typography

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 1

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 2

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 3

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 4

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 5
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 6
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Typography

+

Lid est laborum et dolorum fuga, This is an example inline link. Et harum quidem rerum facilis, This is bold and emphasis cumque nihilse impedit quo minus id quod amets untra dolor amet sad. While this is code block() and following is a pre tag

+
print 'this is pre tag'
+
+

Following is the syntax highlighted code block

+
func getCookie(name string, r interface{}) (*http.Cookie, error) {
+	rd := r.(*http.Request)
+	cookie, err := rd.Cookie(name)
+	if err != nil {
+		return nil, err
+	}
+	return cookie, nil
+}
+
+func setCookie(cookie *http.Cookie, w interface{}) error {
+	// Get write interface registered using `Acquire` method in handlers.
+	wr := w.(http.ResponseWriter)
+	http.SetCookie(wr, cookie)
+	return nil
+}
+

This is blockquote, Will make it better now

+
+

‘I want to do with you what spring does with the cherry trees.’ cited ~Pablo Neruda*

+
+
+

Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit

+
+

Unordered list

+
    +
  • Red
  • +
  • Green
  • +
  • Blue
  • +
+

Ordered list

+
    +
  1. Red
  2. +
  3. Green
  4. +
  5. Blue
  6. +
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2018/03/fearlessness-how-to-stop-running-from-space/index.html b/public/2018/03/fearlessness-how-to-stop-running-from-space/index.html new file mode 100644 index 0000000..d000c56 --- /dev/null +++ b/public/2018/03/fearlessness-how-to-stop-running-from-space/index.html @@ -0,0 +1,159 @@ + + + + Fearlessness: How to Stop Running from Space - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Fearlessness: How to Stop Running from Space

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos.

+

We are afraid of empty space in our lives.

+

The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives.

+

We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. We try to fill every second with activity, with something useful, as if silence and space are not valuable.

+

But what are we afraid of?

+

And who would we be if we didn’t have that fear?

+

We’re afraid of space and stillness and silence because it highlights the uncertainty, instability, groundlessness, insecurity, shakiness that lie underneath every second of our lives. We’re afraid of having to face this instability and uncertainty, of having to feel the fear of it.

+

Without the fear of all of the uncertainty that is highlighted by space … we become free.

+

I know in my life, when I allow myself to have stillness, silence, solitude, simplicity and space … it leaves room to face whatever is coming up for me. It gives me room to fully feel any feelings that I’ve been avoiding. It allows me to be more honest with myself, instead of using distractions and busyness to cover up what I don’t want to see.

+

And in the end, I develop trust that the space is not something to be feared, but rather something to be treasured. A gift, filled with learning and not knowing and shakiness and beauty.

+

You might try allowing more space to be in your day, without filling it:

+
    +
  • Take some time between tasks for stillness.
  • +
  • Sit out in nature, in silence, without technology.
  • +
  • When you notice yourself reaching for your phone, pause. See if you can just be still, just savor some space.
  • +
  • When you feel uncertainty or instability in your life (hint: it’s always there), let yourself feel it. Be present with it, without needing to run or avoid.
  • +
  • When you feel fear, be open-hearted with it and allow yourself fully feel it, being friendly with it. Your relationship with fear will change if you become friendly with it.
  • +
  • Do less, and trust that things won’t fall apart. Or if they do fall apart, you can be present with that instability.
  • +
  • When you’re in line, driving, eating, walking, exercising … see if you can do those things in silence, without technology, without needing to do something “useful.” Find the value in these spaces.
  • +
  • Notice who you are without the fear of space.
  • +
+

Savor these spaces, their deliciousness. Savor the groundlessness, as something filled with freedom if we learn not to fear it. Be present with the fear and uncertainty, as good friends not as enemies.

+

Let your heart be open raw tender and vulnerable, and your mind embracing the spaciousness of the vast blue sky of open awareness.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/index.html b/public/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/index.html new file mode 100644 index 0000000..11a78fe --- /dev/null +++ b/public/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/index.html @@ -0,0 +1,145 @@ + + + + How I Learned to Stop Procrastinating, & Love Letting Go - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

How I Learned to Stop Procrastinating, & Love Letting Go

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

The end of procrastination is the art of letting go.

+

I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done.

+

Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. It stressed me out. My work was less-than-desirable when I did it last minute. Slowly, I started to realize that procrastination wasn’t doing me any favors. In fact, it was causing me a lot of grief.

+

But I couldn’t quit. I tried a lot of things. I tried time boxing and goal setting and accountability and the Pomodoro Technique and Getting Things Done. All are great methods, but they only last so long. Nothing really worked over the long term.

+

That’s because I wasn’t getting to the root problem.

+

I hadn’t figured out the skill that would save me from the procrastination.

+

Until I learned about letting go.

+

Letting go first came to me when I was quitting smoking. I had to let go of the “need” to smoke, the use of my crutch of cigarettes to deal with stress and problems.

+

Then I learned I needed to let go of other false needs that were causing me problems: sugar, junk food, meat, shopping, beer, possessions. I’m not saying I can never do these things again once I let go of these needs, but I let go of the idea that they’re really necessary. I let go of an unhealthy attachment to them.

+

Then I learned that distractions and the false need to check my email and news and other things online … were causing me problems. They were causing my procrastination.

+

So I learned to let go of those too.

+

Here’s the process I used to let go of the distractions and false needs that cause procrastination:

+

I paid attention to the pain they cause me, later, instead of only the temporary comfort/pleasure they gave me right away. +I thought about the person I want to be, the life I want to live. I set my intentions to do the good work I think I should do. +I watched my urges to check things, to go to the comfort of distractions. I saw that I wanted to escape discomfort of something hard, and go to the comfort of something familiar and easy. +I realized I didn’t need that comfort. I could be in discomfort and nothing bad would happen. In fact, the best things happen when I’m in discomfort. +And then I smile, and breathe, and let go.

+

And one step at a time, become the person I want to be.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2018/03/how-to-test-dark-mode/index.html b/public/2018/03/how-to-test-dark-mode/index.html new file mode 100644 index 0000000..6af7640 --- /dev/null +++ b/public/2018/03/how-to-test-dark-mode/index.html @@ -0,0 +1,129 @@ + + + + How to test dark mode? - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

How to test dark mode?

+
Posted on Mar 18, 2018 DRAFT
+
+ +
+ tl;dr: + Wubba lubba dub dub +
+ +
+ +

Table of Contents

+ + +
+ +
+

You can set dark mode as default by setting params.mode to dark in config.toml or set it to auto which will detect based on your OS and switch to dark mode. For more details refer documentation

+

Here is how you can switch based on your OS

+ + +
+ + + + +
+
+ +
+ + diff --git a/public/2018/03/hugo-shortcodes/index.html b/public/2018/03/hugo-shortcodes/index.html new file mode 100644 index 0000000..4654f43 --- /dev/null +++ b/public/2018/03/hugo-shortcodes/index.html @@ -0,0 +1,385 @@ + + + + Hugo shortcodes - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+ +
+ +
+ + diff --git a/public/2018/03/typography/index.html b/public/2018/03/typography/index.html new file mode 100644 index 0000000..4d698f3 --- /dev/null +++ b/public/2018/03/typography/index.html @@ -0,0 +1,181 @@ + + + + Typography - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Typography

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 1

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 2

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 3

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 4

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 5
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 6
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Typography

+

Lid est laborum et dolorum fuga, This is an example inline link. Et harum quidem rerum facilis, This is bold and emphasis cumque nihilse impedit quo minus id quod amets untra dolor amet sad. While this is code block() and following is a pre tag

+
print 'this is pre tag'
+
+

Following is the syntax highlighted code block

+
func getCookie(name string, r interface{}) (*http.Cookie, error) {
+	rd := r.(*http.Request)
+	cookie, err := rd.Cookie(name)
+	if err != nil {
+		return nil, err
+	}
+	return cookie, nil
+}
+
+func setCookie(cookie *http.Cookie, w interface{}) error {
+	// Get write interface registered using `Acquire` method in handlers.
+	wr := w.(http.ResponseWriter)
+	http.SetCookie(wr, cookie)
+	return nil
+}
+

This is blockquote, Will make it better now

+
+

‘I want to do with you what spring does with the cherry trees.’ cited ~Pablo Neruda*

+
+
+

Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit

+
+

Unordered list

+
    +
  • Red
  • +
  • Green
  • +
  • Blue
  • +
+

Ordered list

+
    +
  1. Red
  2. +
  3. Green
  4. +
  5. Blue
  6. +
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/03/18/getting-started-with-traveling-ultralight/index.html b/public/2020/03/18/getting-started-with-traveling-ultralight/index.html new file mode 100644 index 0000000..0918d31 --- /dev/null +++ b/public/2020/03/18/getting-started-with-traveling-ultralight/index.html @@ -0,0 +1,133 @@ + + + + Getting Started with Traveling Ultralight - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Getting Started with Traveling Ultralight

+
Posted on Mar 18, 2020 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said.

+

I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. But then I remembered that I’m far from normal in this way.

+

I gave him a tip for getting started, and I recommend it for all of you, who want to travel light — or ultralight, as I call it, because for many people traveling light is taking a carry-on roller luggage. For me, having those roller bags is lugging too much, because you can run up stairs with it with ease, or carry it all over a city without worrying about stowing away your luggage somewhere first. It’s so much easier to travel ultralight.

+

Here’s the tip I gave him to get started: start by getting a small backpack (less than 20 liters) and then just travel with what fits in that.

+

That’s how to start. But you’ll probably want some guidance on what to put into the bag, and how to travel with so little. Here’s some guidance to get started:

+
    +
  • I travel with a lightweight laptop (Macbook Air), a few clothes, my phone, earbuds and some charging cords, toiletries, and almost nothing else. A lightweight windbreaker for wind and light rain (Patagonia Houdini). An eye mask and ear plugs. A collapsible water bottle. My passport. That’s about it. No extra shoes. No books. No suit. No travel pillow. No extra camera other than my phone. I’m not sure what else everyone else brings, but none of that.
  • +
  • I bring clothes that I can wash in the sink or shower and that will dry overnight. Lightweight stuff that I can layer. Often they’re workout-style clothes or things from companies like Outlier or Patagonia that travel well. I don’t bring enough underwear or socks for every day of the trip, because I wash them every couple of days. I only bring one or two extra T-shirts, generally wearing the same two shirts the whole trip, even if it’s a month long. No one has ever once cared what I wear when I’m traveling.
  • +
  • I bring minimal toiletries: a small shaver for my head, razor, toothbrush, floss small tubes of toothpaste and shaving cream, deodorant, nail clippers, ibuprofen.
  • +
  • For cold places, I have thermal underwear and a couple long-sleeve layers (generally all Patagonia capilene stuff), and a beanie. I don’t usually go to places where it’s snowing (I don’t know why, maybe snow isn’t my thing), so I don’t have clothes to deal with that weather.
  • +
  • For warm places, I will bring flip flops and swim trunks, and leave most of the colder layers behind.
  • +
+

That’s enough for a monthlong trip, which I’ve done multiple times with this kind of setup. For a shorter trip of a few days, I might bring even less.

+

I really love traveling this way, and am more than willing to sacrifice bringing extra things for the luxury of traveling lightweight.

+

By the way, you don’t need much more than this kind of setup even in everyday life.

+

For more info on this, check out my Ultralight ebook, and my friend Tynan has a great book called Forever Nomad.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/03/getting-started-with-traveling-ultralight/index.html b/public/2020/03/getting-started-with-traveling-ultralight/index.html new file mode 100644 index 0000000..650ee04 --- /dev/null +++ b/public/2020/03/getting-started-with-traveling-ultralight/index.html @@ -0,0 +1,133 @@ + + + + Getting Started with Traveling Ultralight - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Getting Started with Traveling Ultralight

+
Posted on Mar 18, 2020 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said.

+

I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. But then I remembered that I’m far from normal in this way.

+

I gave him a tip for getting started, and I recommend it for all of you, who want to travel light — or ultralight, as I call it, because for many people traveling light is taking a carry-on roller luggage. For me, having those roller bags is lugging too much, because you can run up stairs with it with ease, or carry it all over a city without worrying about stowing away your luggage somewhere first. It’s so much easier to travel ultralight.

+

Here’s the tip I gave him to get started: start by getting a small backpack (less than 20 liters) and then just travel with what fits in that.

+

That’s how to start. But you’ll probably want some guidance on what to put into the bag, and how to travel with so little. Here’s some guidance to get started:

+
    +
  • I travel with a lightweight laptop (Macbook Air), a few clothes, my phone, earbuds and some charging cords, toiletries, and almost nothing else. A lightweight windbreaker for wind and light rain (Patagonia Houdini). An eye mask and ear plugs. A collapsible water bottle. My passport. That’s about it. No extra shoes. No books. No suit. No travel pillow. No extra camera other than my phone. I’m not sure what else everyone else brings, but none of that.
  • +
  • I bring clothes that I can wash in the sink or shower and that will dry overnight. Lightweight stuff that I can layer. Often they’re workout-style clothes or things from companies like Outlier or Patagonia that travel well. I don’t bring enough underwear or socks for every day of the trip, because I wash them every couple of days. I only bring one or two extra T-shirts, generally wearing the same two shirts the whole trip, even if it’s a month long. No one has ever once cared what I wear when I’m traveling.
  • +
  • I bring minimal toiletries: a small shaver for my head, razor, toothbrush, floss small tubes of toothpaste and shaving cream, deodorant, nail clippers, ibuprofen.
  • +
  • For cold places, I have thermal underwear and a couple long-sleeve layers (generally all Patagonia capilene stuff), and a beanie. I don’t usually go to places where it’s snowing (I don’t know why, maybe snow isn’t my thing), so I don’t have clothes to deal with that weather.
  • +
  • For warm places, I will bring flip flops and swim trunks, and leave most of the colder layers behind.
  • +
+

That’s enough for a monthlong trip, which I’ve done multiple times with this kind of setup. For a shorter trip of a few days, I might bring even less.

+

I really love traveling this way, and am more than willing to sacrifice bringing extra things for the luxury of traveling lightweight.

+

By the way, you don’t need much more than this kind of setup even in everyday life.

+

For more info on this, check out my Ultralight ebook, and my friend Tynan has a great book called Forever Nomad.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/04/01/primer-when-you-have-too-much-to-do/index.html b/public/2020/04/01/primer-when-you-have-too-much-to-do/index.html new file mode 100644 index 0000000..b37a24b --- /dev/null +++ b/public/2020/04/01/primer-when-you-have-too-much-to-do/index.html @@ -0,0 +1,175 @@ + + + + Primer: When You Have Too Much to Do - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Primer: When You Have Too Much to Do

+
Posted on Apr 1, 2020 DRAFT
+
+ + + + +
+

You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more.

+

It all keeps piling up, and it can feel overwhelming.

+

How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate?

+

In this primer, I’ll look at some key strategies and tactics for taking on an overloaded life with an open heart, lots of energy, and a smile on your face.

+

The First Step: Triage

+

Whether you’re just starting your day, or you’re in the middle of the chaos and just need to find some sanity … the first step is to get into triage mode.

+

Triage, as you probably know, is sorting through the chaos to prioritize: what needs to be done now, what needs to be done today, what needs to be done this week, and what can wait? You’re looking at urgency, but also what’s meaningful and important.

+

Here’s what you might do:

+
    +
  • Pick out the things that need to be done today. Start a Short List for things you’re going to do today. That might be important tasks for big projects, urgent tasks that could result in damage if you don’t act, smaller admin tasks that you really should take care of today, and responding to important messages. I would recommend being ruthless and cutting out as much as you can, having just 5 things on your plate if that’s at all possible. Not everything needs to be done today, and not every email needs to be responded to.
  • +
  • Push some things to tomorrow and the rest of the week. If you have deadlines that can be pushed back (or renegotiated), do that. Spread the work out over the week, even into next week. What needs to be done tomorrow? What can wait a day or two longer?
  • +
  • Eliminate what you can. That might mean just not replying to some messages that aren’t that important and don’t really require a reply. It might mean telling some people that you can’t take on this project after all, or that you need to get out of the commitment that you said you’d do. Yes, this is uncomfortable. For now, just put them on a list called, “To Not Do,” and plan to figure out how to get out of them later.
  • +
+

OK, you have some breathing room and a manageable list now! Let’s shrink that down even further and just pick one thing.

+

Next: Focus on One Thing

+

With a lot on your plate, it’s hard to pick one thing to focus on. But that’s exactly what I’m going to ask you to do.

+

Pick one thing, and give it your focus. Yes, there are a lot of other things you can focus on. Yes, they’re stressing you out and making it hard to focus. But think about it this way: if you allow it all to be in your head all the time, that will always be your mode of being. You’ll always be thinking about everything, stressing out about it all, with a frazzled mind … unless you start shifting.

+

The shift:

+
    +
  • Pick something to focus on. Look at the triaged list from the first section … if you have 5-6 things on this Short List, you can assess whether there’s any super urgent, time-sensitive things you need to take care of. If there are, pick one of them. If not, pick the most important one — probably the one you have been putting off doing.
  • +
  • Clear everything else away. Just for a little bit. Close all browser tabs, turn off notifications, close open applications, put your phone away.
  • +
  • Put that one task before you, and allow yourself to be with it completely. Pour yourself into it. Think of it as a practice, of letting go (of everything else), of focus, of radical simplicity.
  • +
+

When you’re done (or after 15-20 minutes have gone by at least), you can switch to something else. But don’t allow yourself to switch until then.

+

By closing off all exits, by choosing one thing, by giving yourself completely to that thing … you’re now in a different mode that isn’t so stressful or spread thin. You’ve started a shift that will lead to focus and sanity.

+

Third: Schedule Time to Simplify

+

Remember the To Not Do list above? Schedule some time this week to start reducing your projects, saying no to people, getting out of commitments, crossing stuff off your task list … so that you can have some sanity back.

+

There are lots of little things that you’ve said “yes” to that you probably shouldn’t have. That’s why you’re overloaded. Protect your more important work, and your time off, and your peace of mind, by saying “no” to things that aren’t as important.

+

Schedule the time to simplify — you don’t have to do it today, but sometime soon — and you can then not have to worry about the things on your To Not Do list until then.

+

Fourth: Practice Mindful Focus

+

Go through the rest of the day with an attitude of “mindful focus.” That means that you are doing one thing at a time, being as present as you can, switching as little as you can.

+

Think of it as a settling of the mind. A new mode of being. A mindfulness practice (which means you won’t be perfect at it).

+

As you practice mindful focus, you’ll learn to practice doing things with an open heart, with curiosity and gratitude, and even joy. Try these one at a time as you get to do each task on your Short List.

+

You’ll find that you’re not so overloaded, but that each task is just perfect for that moment. And that’s a completely new relationship with the work that you do, and a new relationship with life.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/04/01/telegram-bot-for-github-actions/index.html b/public/2020/04/01/telegram-bot-for-github-actions/index.html new file mode 100644 index 0000000..3e5df3c --- /dev/null +++ b/public/2020/04/01/telegram-bot-for-github-actions/index.html @@ -0,0 +1,469 @@ + + + + Telegram Bot for GitHub Actions - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Telegram Bot for GitHub Actions

+
Posted on Apr 1, 2020 DRAFT
+
+ +
+ tl;dr: + Making GitHub Actions with Js Code +
+ + + +
+

Telegram

+

Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API.

+

GitHub Actions

+

GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. You can build, test and deploy your code with GitHub Actions. All these actions are called workflows and workflows differ in the job they’re doing. These maybe test workflows, build ones or deployment ones. You can find all the actions on GitHub in the marketplace

+

Building the Bot

+

Prerequisites

+
    +
  • Basic JavaScript Knowledge
  • +
  • Basic GitHub Knowledge
  • +
  • Telegram Account
  • +
+
+

There are templates for building actions. Here we’re gonna start from scratch

+
+

Environment Setup

+
    +
  • Node, You can download node from their website
  • +
  • NPM comes with node, so you don’t have to worry about it.
  • +
  • Initialize the Project
  • +
+
$ git init ## initialize a new git repository for version management
+---
+$ npm init
+
    +
  • dotenv, Dotenv can be downloaded via
  • +
+
$ npm i dotenv
+---
+$ yarn add dotenv
+
    +
  • node-telegram-bot-api, node-telegram-bot-api is a simple wrapper for building telegram bots. You can download it via
  • +
+
$ npm i node-telegram-bot-api
+---
+$ yarn add node-telegram-bot-api
+
    +
  • @zeit/ncc, NCC is a Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, GCC-style. It’s a dev dependency and can be downloaded
  • +
+
yarn add --dev @zeit/ncc
+---
+npm i -D @zeit/ncc
+

Folder Structure

+

The dist folder will be automatically created. action.yml will be made

+
.
+├── dist
+│   └── index.js
+├── index.js
+├── action.yml
+├── README.md
+└── package.json
+
    +
  • index.js is the file we’re defining the bot
  • +
  • action.yml is the file we’ll define the action and it’s behaviours
  • +
+

Making the Bot

+

We need to get an API bot token from telegram. For that Go to Telegram and Search for Botfather. It’s a bot. + +Create a new bot with the /newbot command and get the API key. We’ll need that, also talk to jsondump bot and get your chat id. The output may be like this, so

+
{
+  "update_id": 143943779,
+  "message": {
+    "message_id": 181575,
+    "from": {
+      "id": 123456 // this is what we need
+      "is_bot": false,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "language_code": "en"
+    },
+    "chat": {
+      "id": 123456,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "type": "private"
+    },
+    "date": 1584119424,
+    "text": "message"
+  }
+}
+

This will be needed for further use and We need to add it to the repo secrets which can be found in the repo settings. Be careful to add it as token and chat like as shown below +

+

Writing the Action and Building the Bot

+

Fire up the terminal/cmd and make a new folder. Install the dependencies. Run the following command

+
$ touch index.js action.yml
+

Open your favourite text editor within the folder or with the file. We’ll define the bot in index.js

+
require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+const {
+    INPUT_STATUS: ipstatus,
+    INPUT_TOKEN: tgtoken,//Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor,// Issue made by
+    INPUT_IU_BODY: ibody,// Issue Body
+    INPUT_PR_NUM: pnum,// PR Number
+    INPUT_PR_STATE: prstate,// PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle,// PR Title
+    INPUT_PR_BODY: pbody,// Body of the PR
+    GITHUB_EVENT_NAME: ghevent,// Name of the trigger event
+    GITHUB_REPOSITORY: repo,// Repository the trigger was made from
+    GITHUB_ACTOR: ghactor,// User who triggered the action
+    GITHUB_SHA: sha,// Commit ID
+    GITHUB_WORKFLOW: ghwrkflw// Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+

First, we’re defining the dotenv for config and initializing Telegram Bot. Here we’re defining the alias variables for the environment variables. You might notice an INPUT_ for almost every environment variable, this is because GitHub Actions pass the env variable with an INPUT prefix. Other env variables are action’s default environment variables. Then we initialized the bot with the API token.

+

GitHub actions could be triggered with Issues, Pull Request or Pushes. You can find the trigger events here. Here we’re gonna get a message from the bot when an Issue or Pull Request or a Push event has happened.

+
const evresp = (gevent) => {
+    switch (gevent) {
+
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+

In these lines of code, we’re just initializing a switch statement for the responses. We’re also declaring an anonymous function to use the switch responses via a function later. We’re using all the defined variables in the switch. You can check the trigger Events to get how the event is triggered and what keyword should be used.

+

Now for the last part of the Js file, we just take the response from the switch and assign it to a constant. Then we use the sendMessage function of the node-telegram-bot-api to send the message to the bot with the chatid and the output as the arguments.

+
const output = evresp(ghevent)
+

bot.sendMessage(chatid,output,{parse_mode : “Markdown”})

+

Compiling and Minifying the Js code

+

Since we have installed @zeit/ncc and this is used for the making the whole program with all the APIs to a single file and we need to use NCC for that. We just need to run

+
yarn run ncc build index.js -C -m -o dist
+

or you might wanna add the following to you package.json file, and run npm run test to compile and minify the code.

+
"scripts": {
+    "test": "ncc build index.js -C -m -o dist"
+  },
+

This will create a dist folder with and index.js file which contains the compiled code.

+

Making it a valid action

+

For making this Js file a valid action, we need to add an action.yml file. The action.yml for this action is like this

+
name: 'Action Name'
+description: 'Action Descreption'
+author: '<author name>'
+inputs: 
+  chat:
+    description: 'Chat to send: chat id or @channel_name'
+    required: true
+  token:
+    description: 'Telegram Bot token'
+    required: true
+  status:
+    description: 'Job status'
+    required: true
+  iu_title: 
+    description: 'Issue Title'
+    default: ${{ github.event.issue.title }}
+  iu_num:
+    description: 'Issue Number'
+    default: ${{ github.event.issue.number }}
+  iu_actor: 
+    description: 'Issue Triggerer'
+    default: ${{ github.event.issue.user.login }}
+  iu_com:
+    description: 'Issue Comment'
+    default: ${{github.event.comment.body}}
+  pr_state:
+    description: 'State of the PR'
+    default: ${{ github.event.action }}
+  pr_num:
+    description: 'PR Number'
+    default: ${{ github.event.number }}
+  pr_title:
+    description: 'Title of the PR'
+    default: ${{ github.event.pull_request.title }}
+  pr_body:
+    description: 'Body/Contents of the PR'
+    default: ${{ github.event.pull_request.body }}
+runs:
+  using: "node12"
+  main: "dist/index.js"
+branding:
+  icon: 'repeat'  
+  color: 'green'
+

Here we’re defining the Input variables to be loaded for the action in GitHub’s runtime environemt. All these default data are taken from the response of the webhooks which are send by GitHub when a trigger event is occured. You can find out more in the Action Documentation Here.

+
runs:
+  using: "node12"
+  main: "dist/index.js"
+

Here we are defining that this is a node action and should run in an environment with node, and the file which should be run, here the index.js file in the dist folder. That should do it. Create a new commit and push it to a repo. Create a new tag and this action will appear in the marketplace.

+

Defining a workflow to test your action

+

GitHub Action workflows are defined using the .yml syntax. Here is an example of a sample workflow for this action

+
name: <Workflow Name>
+
+on:
+  push:
+  pull_request:
+    types: [opened, closed]
+  issues:
+    types: [opened, closed, reopened]
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: <AnyName>
+        uses: <username>/<repo>@master
+        if: always()
+        with:
+          chat: ${{ secrets.chat }}
+          token: ${{ secrets.token }}
+          status: ${{ job.status }}
+

The Complete code for the bot is

+
//Initializing dotenv and the bot
+require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+// aliasing the environment variables 
+const {
+    INPUT_STATUS: ipstatus, 
+    INPUT_TOKEN: tgtoken, //Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor, // Issue made by
+    INPUT_IU_BODY: ibody, // Issue Body
+    INPUT_PR_NUM: pnum, // PR Number
+    INPUT_PR_STATE: prstate, // PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle, // PR Title
+    INPUT_PR_BODY: pbody, // Body of the PR
+    GITHUB_EVENT_NAME: ghevent, // Name of the trigger event
+    GITHUB_REPOSITORY: repo, // Repository the trigger was made from
+    GITHUB_ACTOR: ghactor, // User who triggered the action
+    GITHUB_SHA: sha, // Commit ID
+    GITHUB_WORKFLOW: ghwrkflw // Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+// Function to return the response for the specific trigger
+const evresp = (gevent) => {
+    switch (gevent) {
+//Switch statement for issues
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+// Switch statement for Pull Requests
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+// switch statement for Pushes
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+// assigning the output to a variable
+const output = evresp(ghevent)
+// sending the message
+bot.sendMessage(chatid,output,{parse_mode : "Markdown"})
+

+

You can try out many different items using actions and this is just a sample action to get you started. Maybe sending Cat GIFs if the build succeded on the pull request or sending a welcome message to a first time contributor. You imagination is the limit😄 and Never Stop being ⚡️

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/04/primer-when-you-have-too-much-to-do/index.html b/public/2020/04/primer-when-you-have-too-much-to-do/index.html new file mode 100644 index 0000000..b9a3249 --- /dev/null +++ b/public/2020/04/primer-when-you-have-too-much-to-do/index.html @@ -0,0 +1,175 @@ + + + + Primer: When You Have Too Much to Do - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Primer: When You Have Too Much to Do

+
Posted on Apr 1, 2020 DRAFT
+
+ + + + +
+

You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more.

+

It all keeps piling up, and it can feel overwhelming.

+

How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate?

+

In this primer, I’ll look at some key strategies and tactics for taking on an overloaded life with an open heart, lots of energy, and a smile on your face.

+

The First Step: Triage

+

Whether you’re just starting your day, or you’re in the middle of the chaos and just need to find some sanity … the first step is to get into triage mode.

+

Triage, as you probably know, is sorting through the chaos to prioritize: what needs to be done now, what needs to be done today, what needs to be done this week, and what can wait? You’re looking at urgency, but also what’s meaningful and important.

+

Here’s what you might do:

+
    +
  • Pick out the things that need to be done today. Start a Short List for things you’re going to do today. That might be important tasks for big projects, urgent tasks that could result in damage if you don’t act, smaller admin tasks that you really should take care of today, and responding to important messages. I would recommend being ruthless and cutting out as much as you can, having just 5 things on your plate if that’s at all possible. Not everything needs to be done today, and not every email needs to be responded to.
  • +
  • Push some things to tomorrow and the rest of the week. If you have deadlines that can be pushed back (or renegotiated), do that. Spread the work out over the week, even into next week. What needs to be done tomorrow? What can wait a day or two longer?
  • +
  • Eliminate what you can. That might mean just not replying to some messages that aren’t that important and don’t really require a reply. It might mean telling some people that you can’t take on this project after all, or that you need to get out of the commitment that you said you’d do. Yes, this is uncomfortable. For now, just put them on a list called, “To Not Do,” and plan to figure out how to get out of them later.
  • +
+

OK, you have some breathing room and a manageable list now! Let’s shrink that down even further and just pick one thing.

+

Next: Focus on One Thing

+

With a lot on your plate, it’s hard to pick one thing to focus on. But that’s exactly what I’m going to ask you to do.

+

Pick one thing, and give it your focus. Yes, there are a lot of other things you can focus on. Yes, they’re stressing you out and making it hard to focus. But think about it this way: if you allow it all to be in your head all the time, that will always be your mode of being. You’ll always be thinking about everything, stressing out about it all, with a frazzled mind … unless you start shifting.

+

The shift:

+
    +
  • Pick something to focus on. Look at the triaged list from the first section … if you have 5-6 things on this Short List, you can assess whether there’s any super urgent, time-sensitive things you need to take care of. If there are, pick one of them. If not, pick the most important one — probably the one you have been putting off doing.
  • +
  • Clear everything else away. Just for a little bit. Close all browser tabs, turn off notifications, close open applications, put your phone away.
  • +
  • Put that one task before you, and allow yourself to be with it completely. Pour yourself into it. Think of it as a practice, of letting go (of everything else), of focus, of radical simplicity.
  • +
+

When you’re done (or after 15-20 minutes have gone by at least), you can switch to something else. But don’t allow yourself to switch until then.

+

By closing off all exits, by choosing one thing, by giving yourself completely to that thing … you’re now in a different mode that isn’t so stressful or spread thin. You’ve started a shift that will lead to focus and sanity.

+

Third: Schedule Time to Simplify

+

Remember the To Not Do list above? Schedule some time this week to start reducing your projects, saying no to people, getting out of commitments, crossing stuff off your task list … so that you can have some sanity back.

+

There are lots of little things that you’ve said “yes” to that you probably shouldn’t have. That’s why you’re overloaded. Protect your more important work, and your time off, and your peace of mind, by saying “no” to things that aren’t as important.

+

Schedule the time to simplify — you don’t have to do it today, but sometime soon — and you can then not have to worry about the things on your To Not Do list until then.

+

Fourth: Practice Mindful Focus

+

Go through the rest of the day with an attitude of “mindful focus.” That means that you are doing one thing at a time, being as present as you can, switching as little as you can.

+

Think of it as a settling of the mind. A new mode of being. A mindfulness practice (which means you won’t be perfect at it).

+

As you practice mindful focus, you’ll learn to practice doing things with an open heart, with curiosity and gratitude, and even joy. Try these one at a time as you get to do each task on your Short List.

+

You’ll find that you’re not so overloaded, but that each task is just perfect for that moment. And that’s a completely new relationship with the work that you do, and a new relationship with life.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/04/telegram-bot-for-github-actions/index.html b/public/2020/04/telegram-bot-for-github-actions/index.html new file mode 100644 index 0000000..8fc6040 --- /dev/null +++ b/public/2020/04/telegram-bot-for-github-actions/index.html @@ -0,0 +1,469 @@ + + + + Telegram Bot for GitHub Actions - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Telegram Bot for GitHub Actions

+
Posted on Apr 1, 2020 DRAFT
+
+ +
+ tl;dr: + Making GitHub Actions with Js Code +
+ + + +
+

Telegram

+

Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API.

+

GitHub Actions

+

GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. You can build, test and deploy your code with GitHub Actions. All these actions are called workflows and workflows differ in the job they’re doing. These maybe test workflows, build ones or deployment ones. You can find all the actions on GitHub in the marketplace

+

Building the Bot

+

Prerequisites

+
    +
  • Basic JavaScript Knowledge
  • +
  • Basic GitHub Knowledge
  • +
  • Telegram Account
  • +
+
+

There are templates for building actions. Here we’re gonna start from scratch

+
+

Environment Setup

+
    +
  • Node, You can download node from their website
  • +
  • NPM comes with node, so you don’t have to worry about it.
  • +
  • Initialize the Project
  • +
+
$ git init ## initialize a new git repository for version management
+---
+$ npm init
+
    +
  • dotenv, Dotenv can be downloaded via
  • +
+
$ npm i dotenv
+---
+$ yarn add dotenv
+
    +
  • node-telegram-bot-api, node-telegram-bot-api is a simple wrapper for building telegram bots. You can download it via
  • +
+
$ npm i node-telegram-bot-api
+---
+$ yarn add node-telegram-bot-api
+
    +
  • @zeit/ncc, NCC is a Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, GCC-style. It’s a dev dependency and can be downloaded
  • +
+
yarn add --dev @zeit/ncc
+---
+npm i -D @zeit/ncc
+

Folder Structure

+

The dist folder will be automatically created. action.yml will be made

+
.
+├── dist
+│   └── index.js
+├── index.js
+├── action.yml
+├── README.md
+└── package.json
+
    +
  • index.js is the file we’re defining the bot
  • +
  • action.yml is the file we’ll define the action and it’s behaviours
  • +
+

Making the Bot

+

We need to get an API bot token from telegram. For that Go to Telegram and Search for Botfather. It’s a bot. + +Create a new bot with the /newbot command and get the API key. We’ll need that, also talk to jsondump bot and get your chat id. The output may be like this, so

+
{
+  "update_id": 143943779,
+  "message": {
+    "message_id": 181575,
+    "from": {
+      "id": 123456 // this is what we need
+      "is_bot": false,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "language_code": "en"
+    },
+    "chat": {
+      "id": 123456,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "type": "private"
+    },
+    "date": 1584119424,
+    "text": "message"
+  }
+}
+

This will be needed for further use and We need to add it to the repo secrets which can be found in the repo settings. Be careful to add it as token and chat like as shown below +

+

Writing the Action and Building the Bot

+

Fire up the terminal/cmd and make a new folder. Install the dependencies. Run the following command

+
$ touch index.js action.yml
+

Open your favourite text editor within the folder or with the file. We’ll define the bot in index.js

+
require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+const {
+    INPUT_STATUS: ipstatus,
+    INPUT_TOKEN: tgtoken,//Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor,// Issue made by
+    INPUT_IU_BODY: ibody,// Issue Body
+    INPUT_PR_NUM: pnum,// PR Number
+    INPUT_PR_STATE: prstate,// PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle,// PR Title
+    INPUT_PR_BODY: pbody,// Body of the PR
+    GITHUB_EVENT_NAME: ghevent,// Name of the trigger event
+    GITHUB_REPOSITORY: repo,// Repository the trigger was made from
+    GITHUB_ACTOR: ghactor,// User who triggered the action
+    GITHUB_SHA: sha,// Commit ID
+    GITHUB_WORKFLOW: ghwrkflw// Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+

First, we’re defining the dotenv for config and initializing Telegram Bot. Here we’re defining the alias variables for the environment variables. You might notice an INPUT_ for almost every environment variable, this is because GitHub Actions pass the env variable with an INPUT prefix. Other env variables are action’s default environment variables. Then we initialized the bot with the API token.

+

GitHub actions could be triggered with Issues, Pull Request or Pushes. You can find the trigger events here. Here we’re gonna get a message from the bot when an Issue or Pull Request or a Push event has happened.

+
const evresp = (gevent) => {
+    switch (gevent) {
+
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+

In these lines of code, we’re just initializing a switch statement for the responses. We’re also declaring an anonymous function to use the switch responses via a function later. We’re using all the defined variables in the switch. You can check the trigger Events to get how the event is triggered and what keyword should be used.

+

Now for the last part of the Js file, we just take the response from the switch and assign it to a constant. Then we use the sendMessage function of the node-telegram-bot-api to send the message to the bot with the chatid and the output as the arguments.

+
const output = evresp(ghevent)
+

bot.sendMessage(chatid,output,{parse_mode : “Markdown”})

+

Compiling and Minifying the Js code

+

Since we have installed @zeit/ncc and this is used for the making the whole program with all the APIs to a single file and we need to use NCC for that. We just need to run

+
yarn run ncc build index.js -C -m -o dist
+

or you might wanna add the following to you package.json file, and run npm run test to compile and minify the code.

+
"scripts": {
+    "test": "ncc build index.js -C -m -o dist"
+  },
+

This will create a dist folder with and index.js file which contains the compiled code.

+

Making it a valid action

+

For making this Js file a valid action, we need to add an action.yml file. The action.yml for this action is like this

+
name: 'Action Name'
+description: 'Action Descreption'
+author: '<author name>'
+inputs: 
+  chat:
+    description: 'Chat to send: chat id or @channel_name'
+    required: true
+  token:
+    description: 'Telegram Bot token'
+    required: true
+  status:
+    description: 'Job status'
+    required: true
+  iu_title: 
+    description: 'Issue Title'
+    default: ${{ github.event.issue.title }}
+  iu_num:
+    description: 'Issue Number'
+    default: ${{ github.event.issue.number }}
+  iu_actor: 
+    description: 'Issue Triggerer'
+    default: ${{ github.event.issue.user.login }}
+  iu_com:
+    description: 'Issue Comment'
+    default: ${{github.event.comment.body}}
+  pr_state:
+    description: 'State of the PR'
+    default: ${{ github.event.action }}
+  pr_num:
+    description: 'PR Number'
+    default: ${{ github.event.number }}
+  pr_title:
+    description: 'Title of the PR'
+    default: ${{ github.event.pull_request.title }}
+  pr_body:
+    description: 'Body/Contents of the PR'
+    default: ${{ github.event.pull_request.body }}
+runs:
+  using: "node12"
+  main: "dist/index.js"
+branding:
+  icon: 'repeat'  
+  color: 'green'
+

Here we’re defining the Input variables to be loaded for the action in GitHub’s runtime environemt. All these default data are taken from the response of the webhooks which are send by GitHub when a trigger event is occured. You can find out more in the Action Documentation Here.

+
runs:
+  using: "node12"
+  main: "dist/index.js"
+

Here we are defining that this is a node action and should run in an environment with node, and the file which should be run, here the index.js file in the dist folder. That should do it. Create a new commit and push it to a repo. Create a new tag and this action will appear in the marketplace.

+

Defining a workflow to test your action

+

GitHub Action workflows are defined using the .yml syntax. Here is an example of a sample workflow for this action

+
name: <Workflow Name>
+
+on:
+  push:
+  pull_request:
+    types: [opened, closed]
+  issues:
+    types: [opened, closed, reopened]
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: <AnyName>
+        uses: <username>/<repo>@master
+        if: always()
+        with:
+          chat: ${{ secrets.chat }}
+          token: ${{ secrets.token }}
+          status: ${{ job.status }}
+

The Complete code for the bot is

+
//Initializing dotenv and the bot
+require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+// aliasing the environment variables 
+const {
+    INPUT_STATUS: ipstatus, 
+    INPUT_TOKEN: tgtoken, //Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor, // Issue made by
+    INPUT_IU_BODY: ibody, // Issue Body
+    INPUT_PR_NUM: pnum, // PR Number
+    INPUT_PR_STATE: prstate, // PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle, // PR Title
+    INPUT_PR_BODY: pbody, // Body of the PR
+    GITHUB_EVENT_NAME: ghevent, // Name of the trigger event
+    GITHUB_REPOSITORY: repo, // Repository the trigger was made from
+    GITHUB_ACTOR: ghactor, // User who triggered the action
+    GITHUB_SHA: sha, // Commit ID
+    GITHUB_WORKFLOW: ghwrkflw // Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+// Function to return the response for the specific trigger
+const evresp = (gevent) => {
+    switch (gevent) {
+//Switch statement for issues
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+// Switch statement for Pull Requests
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+// switch statement for Pushes
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+// assigning the output to a variable
+const output = evresp(ghevent)
+// sending the message
+bot.sendMessage(chatid,output,{parse_mode : "Markdown"})
+

+

You can try out many different items using actions and this is just a sample action to get you started. Maybe sending Cat GIFs if the build succeded on the pull request or sending a welcome message to a first time contributor. You imagination is the limit😄 and Never Stop being ⚡️

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/12/01/hello-r-markdown/index.Rmd b/public/2020/12/01/hello-r-markdown/index.Rmd new file mode 100644 index 0000000..8768d78 --- /dev/null +++ b/public/2020/12/01/hello-r-markdown/index.Rmd @@ -0,0 +1,38 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(collapse = TRUE) +``` + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + +```{r cars} +summary(cars) +fit <- lm(dist ~ speed, data = cars) +fit +``` + +# Including Plots + +You can also embed plots. See Figure \@ref(fig:pie) for example: + +```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE} +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` diff --git a/public/2020/12/01/hello-r-markdown/index.html b/public/2020/12/01/hello-r-markdown/index.html new file mode 100644 index 0000000..1faddc7 --- /dev/null +++ b/public/2020/12/01/hello-r-markdown/index.html @@ -0,0 +1,174 @@ + + + + Hello R Markdown - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Hello R Markdown

+
Posted on Dec 1, 2020 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

R Markdown

+

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

+

You can embed an R code chunk like this:

+
summary(cars)
+##      speed           dist       
+##  Min.   : 4.0   Min.   :  2.00  
+##  1st Qu.:12.0   1st Qu.: 26.00  
+##  Median :15.0   Median : 36.00  
+##  Mean   :15.4   Mean   : 42.98  
+##  3rd Qu.:19.0   3rd Qu.: 56.00  
+##  Max.   :25.0   Max.   :120.00
+fit <- lm(dist ~ speed, data = cars)
+fit
+## 
+## Call:
+## lm(formula = dist ~ speed, data = cars)
+## 
+## Coefficients:
+## (Intercept)        speed  
+##     -17.579        3.932
+

Including Plots

+

You can also embed plots. See Figure 1 for example:

+
par(mar = c(0, 1, 0, 1))
+pie(
+  c(280, 60, 20),
+  c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
+  col = c('#0292D8', '#F7EA39', '#C4B632'),
+  init.angle = -50, border = NA
+)
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/12/01/hello-r-markdown/index_files/figure-html/pie-1.png b/public/2020/12/01/hello-r-markdown/index_files/figure-html/pie-1.png new file mode 100644 index 0000000..eef072f Binary files /dev/null and b/public/2020/12/01/hello-r-markdown/index_files/figure-html/pie-1.png differ diff --git a/public/2020/12/hello-r-markdown/index.Rmd b/public/2020/12/hello-r-markdown/index.Rmd new file mode 100644 index 0000000..8768d78 --- /dev/null +++ b/public/2020/12/hello-r-markdown/index.Rmd @@ -0,0 +1,38 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(collapse = TRUE) +``` + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + +```{r cars} +summary(cars) +fit <- lm(dist ~ speed, data = cars) +fit +``` + +# Including Plots + +You can also embed plots. See Figure \@ref(fig:pie) for example: + +```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE} +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` diff --git a/public/2020/12/hello-r-markdown/index.html b/public/2020/12/hello-r-markdown/index.html new file mode 100644 index 0000000..e9dbf28 --- /dev/null +++ b/public/2020/12/hello-r-markdown/index.html @@ -0,0 +1,174 @@ + + + + Hello R Markdown - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Hello R Markdown

+
Posted on Dec 1, 2020 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

R Markdown

+

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

+

You can embed an R code chunk like this:

+
summary(cars)
+##      speed           dist       
+##  Min.   : 4.0   Min.   :  2.00  
+##  1st Qu.:12.0   1st Qu.: 26.00  
+##  Median :15.0   Median : 36.00  
+##  Mean   :15.4   Mean   : 42.98  
+##  3rd Qu.:19.0   3rd Qu.: 56.00  
+##  Max.   :25.0   Max.   :120.00
+fit <- lm(dist ~ speed, data = cars)
+fit
+## 
+## Call:
+## lm(formula = dist ~ speed, data = cars)
+## 
+## Coefficients:
+## (Intercept)        speed  
+##     -17.579        3.932
+

Including Plots

+

You can also embed plots. See Figure 1 for example:

+
par(mar = c(0, 1, 0, 1))
+pie(
+  c(280, 60, 20),
+  c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
+  col = c('#0292D8', '#F7EA39', '#C4B632'),
+  init.angle = -50, border = NA
+)
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2020/12/hello-r-markdown/index_files/figure-html/pie-1.png b/public/2020/12/hello-r-markdown/index_files/figure-html/pie-1.png new file mode 100644 index 0000000..eef072f Binary files /dev/null and b/public/2020/12/hello-r-markdown/index_files/figure-html/pie-1.png differ diff --git a/public/2024/07/06/new-post-on-archie/index.Rmarkdown b/public/2024/07/06/new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..e9196ed --- /dev/null +++ b/public/2024/07/06/new-post-on-archie/index.Rmarkdown @@ -0,0 +1,25 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? \ No newline at end of file diff --git a/public/2024/07/06/new-post-on-archie/index.html b/public/2024/07/06/new-post-on-archie/index.html new file mode 100644 index 0000000..7e85927 --- /dev/null +++ b/public/2024/07/06/new-post-on-archie/index.html @@ -0,0 +1,148 @@ + + + + New Post on Archie - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

New Post on Archie

+
Posted on Jul 6, 2024
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

Intro

+

This is my first post in the Archie template in hugo.

+

Here’s a random sample from the standard Normal distribution.

+
rnorm(5)
+
## [1] -0.3637057 -0.4214060  0.6501004 -0.8329920  1.3021409
+

Here’s an image of a duck.

+

+

Did I create a html from this?

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db b/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db differ diff --git a/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..3228ebe --- /dev/null +++ b/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,154 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +section: + - intro + - setup + - data +series: "Strength in Data" +tags: ["Strength in Data", "Beginner"] +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 2 + number_sections: true +--- + +```{r setup, include=FALSE, echo = FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../", + tidy = TRUE + ) +options(width = 1000) +``` + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +# Introduction and Objective + +This article provides an overview of *Trabajo de las Mesas*, a pivotal database that will be central to this project. + +The article will also provide guidance on how to connect to the database from within `R`. + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM [^1]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +[^1]: Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture. + + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +For some musings on TdlM, data quality and assumptions made, see this [post](/2024/07/data-quality-musings/). + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download, message = FALSE} +library(here) + +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +db_file_name <- "taskmaster.db" +data_dir <- here("static", "data") + +db_data_location <- file.path(data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(data_dir))){ + dir.create(file.path(data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` + +## Connecting to the `.db` file + +Now that the database file has been successfully downloaded, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + +## Querying the Database + +Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation + +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts +LEFT JOIN people tp +ON ts.id = tp.series +AND ts.champion = tp.id +WHERE ts.special <> 1 +" + +results <- dbGetQuery(tm_db, query) +results +``` + +The results of this query already indicate interesting insights, namely that 204 days (approximately `r round(204/7)` weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag? + +# Times Up! + +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/index.html b/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/index.html new file mode 100644 index 0000000..c8bb050 --- /dev/null +++ b/public/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/index.html @@ -0,0 +1,274 @@ + + + + Strength in Data: Connecting to the Taskmaster Database - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Strength in Data: Connecting to the Taskmaster Database

+
Posted on Jul 10, 2024
+
+ + + + +
+

Your Task

+
+

Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now!

+
+

Introduction and Objective

+

This article provides an overview of Trabajo de las Mesas, a pivotal database that will be central to this project.

+

The article will also provide guidance on how to connect to the database from within R.

+

Trabajo de las Mesas Database

+

Trabajo de las Mesas (TdlM 1) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant.

+

The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project.

+

For some musings on TdlM, data quality and assumptions made, see this post.

+

Connecting to the Database from R

+

Downloading the .db file

+

It is possible to view and query these the numerous tables in TdlM from the website itself. However, this does not lead intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as R or python, naturally leads to repeatablility and reproduceability.

+

I opting choosing to choose R for this project due to my familarity with it, and the high level visualisations and modelling that can be employed.

+

The tables displayed on the website are powered from the following database file which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist.

+
library(here)
+
+# URL where Database file resides. We will download from here.
+db_url <- "https://tdlm.fly.dev/taskmaster.db"
+
+# Where the data will be stored locally
+db_file_name <- "taskmaster.db"
+data_dir <- here("static", "data")
+
+db_data_location <- file.path(data_dir, db_file_name)
+
+
+# Create Data Directory if does not exist
+if (!file.exists(file.path(data_dir))) {
+    dir.create(file.path(data_dir))
+}
+
+# Download file specified by URL, save in the local destination.
+if (!file.exists(db_data_location)) {
+    download.file(url = db_url, destfile = db_data_location, mode = "wb")
+}
+

Connecting to the .db file

+

Now that the database file has been successfully downloaded, we can start to connect to it from R directory. The DBI package will be employed to establish this connection.

+
package_name <- "RSQLite"
+
+if (!require(package_name, character.only = TRUE)) {
+    install.packages(package_name, character.only = TRUE)
+} else {
+    library(package_name, character.only = TRUE)
+}
+
## Loading required package: RSQLite
+
# Driver used to establish database connection
+sqlite_driver <- dbDriver("SQLite")
+
+# Making the connection
+tm_db <- dbConnect(sqlite_driver, dbname = db_data_location)
+

If successful, we should be able to list all the tables included in the database.

+
# List all tables that are available in the database
+dbListTables(tm_db)
+
##  [1] "attempts"           "discrepancies"      "episode_scores"     "episodes"           "intros"             "measurements"       "normalized_scores"  "objectives"         "people"             "podcast"            "profanity"          "series"             "series_scores"      "special_locations"  "task_briefs"        "task_readers"       "task_winners"       "tasks"              "tasks_by_objective" "team_tasks"         "teams"              "title_coiners"      "title_stats"
+

Querying the Database

+

Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from R to access the data. For example:

+

A Basic SELECT query

+
# A Basic Select query on the series table.
+query <- "SELECT * FROM series LIMIT 10"
+
+dbGetQuery(tm_db, query)
+
##    id     name episodes champion  air_start    air_end studio_start studio_end points tasks special TMI
+## 1  -7  CoC III        0       NA 2024-??-?? 2024-??-??   2023-11-28 2023-11-28     NA    NA       1  88
+## 2  -6 NYT 2024        0       NA 2024-01-01 2024-01-01   2023-11-27 2023-11-27     NA    NA       1  87
+## 3  -5 NYT 2023        1       96 2023-01-01 2023-01-01   2022-11-22 2022-11-22     76     5       1  66
+## 4  -4   CoC II        1       87 2022-06-23 2022-06-23   2021-09-15 2021-09-15     66     5       1  46
+## 5  -3 NYT 2022        1       73 2022-01-01 2022-01-01         <NA>       <NA>     68     5       1  47
+## 6  -2 NYT 2021        1       62 2021-01-01 2021-01-01         <NA>       <NA>     62     5       1  12
+## 7  -1      CoC        2       29 2017-12-13 2017-12-20   2017-11-20 2017-11-20    164    10       1   6
+## 8   1 Series 1        6        4 2015-07-28 2015-09-01   2015-03-23 2015-03-25    436    32       0   1
+## 9   2 Series 2        5       11 2016-06-21 2016-07-19         <NA>       <NA>    417    28       0   2
+## 10  3 Series 3        5       16 2016-10-04 2016-11-01         <NA>       <NA>    386    27       0   3
+

Advanced query

+

A more involved query involving JOIN and date manipulation

+
# A join, and data manipulation
+query <- "SELECT ts.name,
+ts.special as special_flag,
+tp.name as champion_name,
+tp.seat as chamption_seat,
+DATE(ts.studio_end) as studio_end, 
+DATE(ts.air_start) as air_start, 
+JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days
+FROM series ts
+LEFT JOIN people tp
+ON ts.id = tp.series
+AND ts.champion = tp.id
+WHERE ts.special <> 1
+"
+
+results <- dbGetQuery(tm_db, query)
+results
+
##         name special_flag    champion_name chamption_seat studio_end  air_start broadcast_lag_days
+## 1   Series 1            0  Josh Widdicombe              2 2015-03-25 2015-07-28                125
+## 2   Series 2            0   Katherine Ryan              4       <NA> 2016-06-21                 NA
+## 3   Series 3            0      Rob Beckett              4       <NA> 2016-10-04                 NA
+## 4   Series 4            0    Noel Fielding              5       <NA> 2017-04-25                 NA
+## 5   Series 5            0     Bob Mortimer              2 2017-07-06 2017-09-13                 69
+## 6   Series 6            0     Liza Tarbuck              3 2018-03-28 2018-05-02                 35
+## 7   Series 7            0   Kerry Godliman              3 2018-07-25 2018-09-05                 42
+## 8   Series 8            0      Lou Sanders              3 2019-03-27 2019-05-08                 42
+## 9   Series 9            0        Ed Gamble              2 2019-07-24 2019-09-04                 42
+## 10 Series 10            0  Richard Herring              5 2020-07-29 2020-10-15                 78
+## 11 Series 11            0    Sarah Kendall              5       <NA> 2021-03-18                 NA
+## 12 Series 12            0 Morgana Robinson              4       <NA> 2021-09-23                 NA
+## 13 Series 13            0     Sophie Duker              5 2021-09-22 2022-04-14                204
+## 14 Series 14            0    Dara Ó Briain              1 2022-05-05 2022-09-29                147
+## 15 Series 15            0       Mae Martin              5 2022-09-28 2023-03-30                183
+## 16 Series 16            0     Sam Campbell              3 2023-05-12 2023-09-21                132
+

The results of this query already indicate interesting insights, namely that 204 days (approximately 29 weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag?

+

Times Up!

+

And that concludes this task! Hopefully you’ve been able to connect to the TdlM database directly through R and potentially inspired to start performing your own analysis.

+
+
+
    +
  1. +

    Taskmaster fanatics will know that this is in reference to the hint in S2E5’s task Build a bridge for the potato., which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture. ↩︎

    +
  2. +
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2024/07/17/data-quality-musings/index.Rmd b/public/2024/07/17/data-quality-musings/index.Rmd new file mode 100644 index 0000000..bc496f5 --- /dev/null +++ b/public/2024/07/17/data-quality-musings/index.Rmd @@ -0,0 +1,49 @@ +--- +title: "Sidenote: Musings on TdlM" +author: Christopher Nam +date: '2024-07-17' +slug: data-quality-musings +categories: [] +tags: ["Musings", "TdlM"] +draft: no +--- + +# Sidenote Introduction +A few remarks and musings on the [Trabajo de las Mesas database (TdlM)](https://tdlm.fly.dev/). + +## Data Quality + +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occur and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + +## Why This Datasource? + +As Taskmaster is a global phenomena, there is no doubt other data sources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + +However, for the purposes of this project, being able to query from database has several advantages. This includes: + +- **Quality:** Data being in a structured tabular format which often leads to better data quality +- **Manipulations:** Greater manipulation and transformations could potentially be employed (joins, group bys etc) +- **Automation, Repeatability and Scalabilty:** if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis through a visual interface. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + +## Potential Articles to Explore in the Future + +- **Greater understanding of how the data is being collected.** + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- **Generate a data dictionary page** + - What tables are available, samples of the data, what the table pertains to, and key columns. +- **A dashboard on data quality.** + - A highlevel overview of the quality and how recent the data is. + - Can we be proactive in identifying data quality issues and resolve them before users of the data experience them. + diff --git a/public/2024/07/17/data-quality-musings/index.html b/public/2024/07/17/data-quality-musings/index.html new file mode 100644 index 0000000..5ac2668 --- /dev/null +++ b/public/2024/07/17/data-quality-musings/index.html @@ -0,0 +1,179 @@ + + + + Sidenote: Musings on TdlM - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Sidenote: Musings on TdlM

+
Posted on Jul 17, 2024
+
+ + +
+ +
+ +
+ + + +
+

Sidenote Introduction

+

A few remarks and musings on the Trabajo de las Mesas database (TdlM).

+
+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource.

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occur and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+
+
+

Why This Datasource?

+

As Taskmaster is a global phenomena, there is no doubt other data sources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis through a visual interface.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+
+
+

Potential Articles to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
    • Can we be proactive in identifying data quality issues and resolve them before users of the data experience them.
    • +
  • +
+
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2024/07/31/data-quality-musings/index.Rmd b/public/2024/07/31/data-quality-musings/index.Rmd new file mode 100644 index 0000000..1730304 --- /dev/null +++ b/public/2024/07/31/data-quality-musings/index.Rmd @@ -0,0 +1,48 @@ +--- +title: "Sidenote: Musings on TdlM" +author: Christopher Nam +date: '2024-07-17' +slug: data-quality-musings +categories: [] +tags: ["musings", "TdlM"] +draft: no +--- + +# Sidenote Introduction +A few remarks and musings on the [Trabajo de las Mesas database (TdlM)](https://tdlm.fly.dev/). + +## Data Quality + +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + +## Why This Datasource? + +As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + +However, for the purposes of this project, being able to query from database has several advantages. This includes: + +- Quality: Data being in a structured tabular format which often leads to better data quality +- Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc) +- Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + +## Potential Areas to Explore in the Future + +- Greater understanding of how the data is being collected. + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- Generate a data dictionary page + - What tables are available, samples of the data, what the table pertains to, and key columns. +- A dashboard on data quality. + - A highlevel overview of the quality and how recent the data is. + diff --git a/public/2024/07/31/data-quality-musings/index.html b/public/2024/07/31/data-quality-musings/index.html new file mode 100644 index 0000000..cec3782 --- /dev/null +++ b/public/2024/07/31/data-quality-musings/index.html @@ -0,0 +1,178 @@ + + + + Sidenote: Musings on TdlM - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Sidenote: Musings on TdlM

+
Posted on Jul 31, 2024
+
+ + +
+ +
+ +
+ + + +
+

Sidenote Introduction

+

A few remarks and musings on the Trabajo de las Mesas database (TdlM).

+
+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource.

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+
+
+

Why This Datasource?

+

As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+
+
+

Potential Areas to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
  • +
+
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2024/07/data-quality-musings/index.Rmd b/public/2024/07/data-quality-musings/index.Rmd new file mode 100644 index 0000000..65f0c3d --- /dev/null +++ b/public/2024/07/data-quality-musings/index.Rmd @@ -0,0 +1,55 @@ +--- +title: "Sidenote: Musings on TdlM" +author: Christopher Nam +date: '2024-07-17' +slug: data-quality-musings +categories: [] +tags: ["Musings", "TdlM"] +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 2 + number_sections: false + df_print: "default" +--- + +# Sidenote Introduction +A few remarks and musings on the [Trabajo de las Mesas database (TdlM)](https://tdlm.fly.dev/). + +## Data Quality + +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occur and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + +## Why This Datasource? + +As Taskmaster is a global phenomena, there is no doubt other data sources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + +However, for the purposes of this project, being able to query from database has several advantages. This includes: + +- **Quality:** Data being in a structured tabular format which often leads to better data quality +- **Manipulations:** Greater manipulation and transformations could potentially be employed (joins, group bys etc) +- **Automation, Repeatability and Scalabilty:** if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis through a visual interface. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + +## Potential Articles to Explore in the Future + +- **Greater understanding of how the data is being collected.** + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- **Generate a data dictionary page** + - What tables are available, samples of the data, what the table pertains to, and key columns. +- **A dashboard on data quality.** + - A highlevel overview of the quality and how recent the data is. + - Can we be proactive in identifying data quality issues and resolve them before users of the data experience them. + diff --git a/public/2024/07/data-quality-musings/index.html b/public/2024/07/data-quality-musings/index.html new file mode 100644 index 0000000..e030874 --- /dev/null +++ b/public/2024/07/data-quality-musings/index.html @@ -0,0 +1,189 @@ + + + + Sidenote: Musings on TdlM - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Sidenote: Musings on TdlM

+
Posted on Jul 17, 2024
+
+ + +
+ +
+ +
+ + + + +
+

Sidenote Introduction

+

A few remarks and musings on the Trabajo de las Mesas database (TdlM).

+
+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource.

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occur and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+
+
+

Why This Datasource?

+

As Taskmaster is a global phenomena, there is no doubt other data sources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis through a visual interface.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+
+
+

Potential Articles to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
    • Can we be proactive in identifying data quality issues and resolve them before users of the data experience them.
    • +
  • +
+
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2024/07/new-post-on-archie/index.Rmarkdown b/public/2024/07/new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..e9196ed --- /dev/null +++ b/public/2024/07/new-post-on-archie/index.Rmarkdown @@ -0,0 +1,25 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? \ No newline at end of file diff --git a/public/2024/07/new-post-on-archie/index.html b/public/2024/07/new-post-on-archie/index.html new file mode 100644 index 0000000..47d2dd8 --- /dev/null +++ b/public/2024/07/new-post-on-archie/index.html @@ -0,0 +1,148 @@ + + + + New Post on Archie - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

New Post on Archie

+
Posted on Jul 6, 2024
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

Intro

+

This is my first post in the Archie template in hugo.

+

Here’s a random sample from the standard Normal distribution.

+
rnorm(5)
+
## [1] -0.3637057 -0.4214060  0.6501004 -0.8329920  1.3021409
+

Here’s an image of a duck.

+

+

Did I create a html from this?

+ +
+ + + + +
+
+ +
+ + diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..53dfb90 --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,162 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +section: + - intro + - setup + - data +series: "Strength in Data" +tags: ["Strength in Data", "Beginner"] +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 2 + number_sections: true + df_print: "default" +--- + +```{r setup, include=FALSE, echo = FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../", + tidy = TRUE + ) +options(width = 1000) +``` + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +This article provides an overview of *Trabajo de las Mesas*, a pivotal database that will be central to this project. + +The article will also provide guidance on how to connect to the database from within `R`. + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM [^1]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +[^1]: Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture. + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +For some musings on TdlM, data quality and assumptions made, see this [post](/2024/07/data-quality-musings/). + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead intuitively to repeatable and reproduceable analysis. Connecting to the database from a (statistical) programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I am opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download, message = FALSE} +library(here) #library to help with identifying the repo working directory + +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +db_file_name <- "taskmaster.db" +data_dir <- here("static", "data") + +db_data_location <- file.path(data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(data_dir))){ + dir.create(file.path(data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` + +## Connecting to the `.db` file + +Now that the database file has been downloaded successfully, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +# Install packages if does not exist, then load. +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + +## Querying the Database +With the database connection established, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation is also possible. + +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +-- Days between air start date, and last studio record date +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts -- Series information +LEFT JOIN people tp -- People/Contestant information + ON ts.id = tp.series + AND ts.champion = tp.id +WHERE ts.special <> 1 -- Consider regular series +" + +results <- dbGetQuery(tm_db, query) + +results +``` + +```{r longest_lag, include = FALSE} +longest_lag_df <- results[which.max(results$broadcast_lag_days),] +``` + +# A recording to airing insight... +The results of this query already indicate interesting insights; `r longest_lag_df$name` has the largest known delay between studio recording and airing of `r longest_lag_df$broadcast_lag_days` days (approximately `r round(longest_lag_df$broadcast_lag_days/7)` weeks). This is a noticeable deviation from prior series. Future series also seem delayed, although to a lesser extent. + +**Potential followup questions:** +- Could the 2020 pandemic have initiated this lag? +- Were there other production changes that led to this lag? + +# Times Up! +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index.html b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index.html new file mode 100644 index 0000000..17ef918 --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index.html @@ -0,0 +1,282 @@ + + + + Strength in Data: Connecting to the Taskmaster Database - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Strength in Data: Connecting to the Taskmaster Database

+
Posted on Jul 10, 2024
+
+ + + + +
+

Your Task

+
+

Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now!

+
+

This article provides an overview of Trabajo de las Mesas, a pivotal database that will be central to this project.

+

The article will also provide guidance on how to connect to the database from within R.

+

Trabajo de las Mesas Database

+

Trabajo de las Mesas (TdlM 1) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant.

+

The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project.

+

For some musings on TdlM, data quality and assumptions made, see this post.

+

Connecting to the Database from R

+

Downloading the .db file

+

It is possible to view and query these the numerous tables in TdlM from the website itself. However, this does not lead intuitively to repeatable and reproduceable analysis. Connecting to the database from a (statistical) programming language such as R or python, naturally leads to repeatablility and reproduceability.

+

I am opting choosing to choose R for this project due to my familarity with it, and the high level visualisations and modelling that can be employed.

+

The tables displayed on the website are powered from the following database file which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist.

+
library(here)  #library to help with identifying the repo working directory
+
+# URL where Database file resides. We will download from here.
+db_url <- "https://tdlm.fly.dev/taskmaster.db"
+
+# Where the data will be stored locally
+db_file_name <- "taskmaster.db"
+data_dir <- here("static", "data")
+
+db_data_location <- file.path(data_dir, db_file_name)
+
+
+# Create Data Directory if does not exist
+if (!file.exists(file.path(data_dir))) {
+    dir.create(file.path(data_dir))
+}
+
+# Download file specified by URL, save in the local destination.
+if (!file.exists(db_data_location)) {
+    download.file(url = db_url, destfile = db_data_location, mode = "wb")
+}
+

Connecting to the .db file

+

Now that the database file has been downloaded successfully, we can start to connect to it from R directory. The DBI package will be employed to establish this connection.

+
package_name <- "RSQLite"
+
+# Install packages if does not exist, then load.
+if (!require(package_name, character.only = TRUE)) {
+    install.packages(package_name, character.only = TRUE)
+} else {
+    library(package_name, character.only = TRUE)
+}
+
## Loading required package: RSQLite
+
# Driver used to establish database connection
+sqlite_driver <- dbDriver("SQLite")
+
+# Making the connection
+tm_db <- dbConnect(sqlite_driver, dbname = db_data_location)
+

If successful, we should be able to list all the tables included in the database.

+
# List all tables that are available in the database
+dbListTables(tm_db)
+
##  [1] "attempts"           "discrepancies"      "episode_scores"     "episodes"           "intros"             "measurements"       "normalized_scores"  "objectives"         "people"             "podcast"            "profanity"          "series"             "series_scores"      "special_locations"  "task_briefs"        "task_readers"       "task_winners"       "tasks"              "tasks_by_objective" "team_tasks"         "teams"              "title_coiners"      "title_stats"
+

Querying the Database

+

With the database connection established, we are able to write queries and execute them directly from R to access the data. For example:

+

A Basic SELECT query

+
# A Basic Select query on the series table.
+query <- "SELECT * FROM series LIMIT 10"
+
+dbGetQuery(tm_db, query)
+
##    id     name episodes champion  air_start    air_end studio_start studio_end points tasks special TMI
+## 1  -7  CoC III        0       NA 2024-??-?? 2024-??-??   2023-11-28 2023-11-28     NA    NA       1  88
+## 2  -6 NYT 2024        0       NA 2024-01-01 2024-01-01   2023-11-27 2023-11-27     NA    NA       1  87
+## 3  -5 NYT 2023        1       96 2023-01-01 2023-01-01   2022-11-22 2022-11-22     76     5       1  66
+## 4  -4   CoC II        1       87 2022-06-23 2022-06-23   2021-09-15 2021-09-15     66     5       1  46
+## 5  -3 NYT 2022        1       73 2022-01-01 2022-01-01         <NA>       <NA>     68     5       1  47
+## 6  -2 NYT 2021        1       62 2021-01-01 2021-01-01         <NA>       <NA>     62     5       1  12
+## 7  -1      CoC        2       29 2017-12-13 2017-12-20   2017-11-20 2017-11-20    164    10       1   6
+## 8   1 Series 1        6        4 2015-07-28 2015-09-01   2015-03-23 2015-03-25    436    32       0   1
+## 9   2 Series 2        5       11 2016-06-21 2016-07-19         <NA>       <NA>    417    28       0   2
+## 10  3 Series 3        5       16 2016-10-04 2016-11-01         <NA>       <NA>    386    27       0   3
+

Advanced query

+

A more involved query involving JOIN and date manipulation is also possible.

+
# A join, and data manipulation
+query <- "SELECT ts.name,
+ts.special as special_flag,
+tp.name as champion_name,
+tp.seat as chamption_seat,
+DATE(ts.studio_end) as studio_end, 
+DATE(ts.air_start) as air_start, 
+-- Days between air start date, and last studio record date
+JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days
+FROM series ts -- Series information
+LEFT JOIN people tp -- People/Contestant information
+    ON ts.id = tp.series
+    AND ts.champion = tp.id
+WHERE ts.special <> 1 -- Consider regular series
+"
+
+results <- dbGetQuery(tm_db, query)
+
+results
+
##         name special_flag    champion_name chamption_seat studio_end  air_start broadcast_lag_days
+## 1   Series 1            0  Josh Widdicombe              2 2015-03-25 2015-07-28                125
+## 2   Series 2            0   Katherine Ryan              4       <NA> 2016-06-21                 NA
+## 3   Series 3            0      Rob Beckett              4       <NA> 2016-10-04                 NA
+## 4   Series 4            0    Noel Fielding              5       <NA> 2017-04-25                 NA
+## 5   Series 5            0     Bob Mortimer              2 2017-07-06 2017-09-13                 69
+## 6   Series 6            0     Liza Tarbuck              3 2018-03-28 2018-05-02                 35
+## 7   Series 7            0   Kerry Godliman              3 2018-07-25 2018-09-05                 42
+## 8   Series 8            0      Lou Sanders              3 2019-03-27 2019-05-08                 42
+## 9   Series 9            0        Ed Gamble              2 2019-07-24 2019-09-04                 42
+## 10 Series 10            0  Richard Herring              5 2020-07-29 2020-10-15                 78
+## 11 Series 11            0    Sarah Kendall              5       <NA> 2021-03-18                 NA
+## 12 Series 12            0 Morgana Robinson              4       <NA> 2021-09-23                 NA
+## 13 Series 13            0     Sophie Duker              5 2021-09-22 2022-04-14                204
+## 14 Series 14            0    Dara Ó Briain              1 2022-05-05 2022-09-29                147
+## 15 Series 15            0       Mae Martin              5 2022-09-28 2023-03-30                183
+## 16 Series 16            0     Sam Campbell              3 2023-05-12 2023-09-21                132
+

A recording to airing insight…

+

The results of this query already indicate interesting insights; Series 13 has the largest known delay between studio recording and airing of 204 days (approximately 29 weeks). This is a noticeable deviation from prior series. Future series also seem delayed, although to a lesser extent.

+

Potential followup questions:

+
    +
  • Could the 2020 pandemic have initiated this lag?
  • +
  • Were there other production changes that led to this lag?
  • +
+

Times Up!

+

And that concludes this task! Hopefully you’ve been able to connect to the TdlM database directly through R and potentially inspired to start performing your own analysis.

+
+
+
    +
  1. +

    Taskmaster fanatics will know that this is in reference to the hint in S2E5’s task Build a bridge for the potato., which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture. ↩︎

    +
  2. +
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/css/crosstalk.min.css b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/css/crosstalk.min.css new file mode 100644 index 0000000..6b45382 --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/css/crosstalk.min.css @@ -0,0 +1 @@ +.container-fluid.crosstalk-bscols{margin-left:-30px;margin-right:-30px;white-space:normal}body>.container-fluid.crosstalk-bscols{margin-left:auto;margin-right:auto}.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:inline-block;padding-right:12px;vertical-align:top}@media only screen and (max-width: 480px){.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column{display:block;padding-right:inherit}}.crosstalk-input{margin-bottom:15px}.crosstalk-input .control-label{margin-bottom:0;vertical-align:middle}.crosstalk-input input[type="checkbox"]{margin:4px 0 0;margin-top:1px;line-height:normal}.crosstalk-input .checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.crosstalk-input .checkbox>label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.crosstalk-input .checkbox input[type="checkbox"],.crosstalk-input .checkbox-inline input[type="checkbox"]{position:absolute;margin-top:2px;margin-left:-20px}.crosstalk-input .checkbox+.checkbox{margin-top:-5px}.crosstalk-input .checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.crosstalk-input .checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px} diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js new file mode 100644 index 0000000..fd9eb53 --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js @@ -0,0 +1,1474 @@ +(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b) { + return 1; + } +} + +/** + * @private + */ + +var FilterSet = function () { + function FilterSet() { + _classCallCheck(this, FilterSet); + + this.reset(); + } + + _createClass(FilterSet, [{ + key: "reset", + value: function reset() { + // Key: handle ID, Value: array of selected keys, or null + this._handles = {}; + // Key: key string, Value: count of handles that include it + this._keys = {}; + this._value = null; + this._activeHandles = 0; + } + }, { + key: "update", + value: function update(handleId, keys) { + if (keys !== null) { + keys = keys.slice(0); // clone before sorting + keys.sort(naturalComparator); + } + + var _diffSortedLists = (0, _util.diffSortedLists)(this._handles[handleId], keys), + added = _diffSortedLists.added, + removed = _diffSortedLists.removed; + + this._handles[handleId] = keys; + + for (var i = 0; i < added.length; i++) { + this._keys[added[i]] = (this._keys[added[i]] || 0) + 1; + } + for (var _i = 0; _i < removed.length; _i++) { + this._keys[removed[_i]]--; + } + + this._updateValue(keys); + } + + /** + * @param {string[]} keys Sorted array of strings that indicate + * a superset of possible keys. + * @private + */ + + }, { + key: "_updateValue", + value: function _updateValue() { + var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._allKeys; + + var handleCount = Object.keys(this._handles).length; + if (handleCount === 0) { + this._value = null; + } else { + this._value = []; + for (var i = 0; i < keys.length; i++) { + var count = this._keys[keys[i]]; + if (count === handleCount) { + this._value.push(keys[i]); + } + } + } + } + }, { + key: "clear", + value: function clear(handleId) { + if (typeof this._handles[handleId] === "undefined") { + return; + } + + var keys = this._handles[handleId]; + if (!keys) { + keys = []; + } + + for (var i = 0; i < keys.length; i++) { + this._keys[keys[i]]--; + } + delete this._handles[handleId]; + + this._updateValue(); + } + }, { + key: "value", + get: function get() { + return this._value; + } + }, { + key: "_allKeys", + get: function get() { + var allKeys = Object.keys(this._keys); + allKeys.sort(naturalComparator); + return allKeys; + } + }]); + + return FilterSet; +}(); + +exports.default = FilterSet; + +},{"./util":11}],4:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.default = group; + +var _var2 = require("./var"); + +var _var3 = _interopRequireDefault(_var2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// Use a global so that multiple copies of crosstalk.js can be loaded and still +// have groups behave as singletons across all copies. +global.__crosstalk_groups = global.__crosstalk_groups || {}; +var groups = global.__crosstalk_groups; + +function group(groupName) { + if (groupName && typeof groupName === "string") { + if (!groups.hasOwnProperty(groupName)) { + groups[groupName] = new Group(groupName); + } + return groups[groupName]; + } else if ((typeof groupName === "undefined" ? "undefined" : _typeof(groupName)) === "object" && groupName._vars && groupName.var) { + // Appears to already be a group object + return groupName; + } else if (Array.isArray(groupName) && groupName.length == 1 && typeof groupName[0] === "string") { + return group(groupName[0]); + } else { + throw new Error("Invalid groupName argument"); + } +} + +var Group = function () { + function Group(name) { + _classCallCheck(this, Group); + + this.name = name; + this._vars = {}; + } + + _createClass(Group, [{ + key: "var", + value: function _var(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + if (!this._vars.hasOwnProperty(name)) this._vars[name] = new _var3.default(this, name); + return this._vars[name]; + } + }, { + key: "has", + value: function has(name) { + if (!name || typeof name !== "string") { + throw new Error("Invalid var name"); + } + + return this._vars.hasOwnProperty(name); + } + }]); + + return Group; +}(); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./var":12}],5:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _selection = require("./selection"); + +var _filter = require("./filter"); + +var _input = require("./input"); + +require("./input_selectize"); + +require("./input_checkboxgroup"); + +require("./input_slider"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var defaultGroup = (0, _group2.default)("default"); + +function var_(name) { + return defaultGroup.var(name); +} + +function has(name) { + return defaultGroup.has(name); +} + +if (global.Shiny) { + global.Shiny.addCustomMessageHandler("update-client-value", function (message) { + if (typeof message.group === "string") { + (0, _group2.default)(message.group).var(message.name).set(message.value); + } else { + var_(message.name).set(message.value); + } + }); +} + +var crosstalk = { + group: _group2.default, + var: var_, + has: has, + SelectionHandle: _selection.SelectionHandle, + FilterHandle: _filter.FilterHandle, + bind: _input.bind +}; + +/** + * @namespace crosstalk + */ +exports.default = crosstalk; + +global.crosstalk = crosstalk; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./group":4,"./input":6,"./input_checkboxgroup":7,"./input_selectize":8,"./input_slider":9,"./selection":10}],6:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.register = register; +exports.bind = bind; +var $ = global.jQuery; + +var bindings = {}; + +function register(reg) { + bindings[reg.className] = reg; + if (global.document && global.document.readyState !== "complete") { + $(function () { + bind(); + }); + } else if (global.document) { + setTimeout(bind, 100); + } +} + +function bind() { + Object.keys(bindings).forEach(function (className) { + var binding = bindings[className]; + $("." + binding.className).not(".crosstalk-input-bound").each(function (i, el) { + bindInstance(binding, el); + }); + }); +} + +// Escape jQuery identifier +function $escape(val) { + return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1"); +} + +function bindEl(el) { + var $el = $(el); + Object.keys(bindings).forEach(function (className) { + if ($el.hasClass(className) && !$el.hasClass("crosstalk-input-bound")) { + var binding = bindings[className]; + bindInstance(binding, el); + } + }); +} + +function bindInstance(binding, el) { + var jsonEl = $(el).find("script[type='application/json'][data-for='" + $escape(el.id) + "']"); + var data = JSON.parse(jsonEl[0].innerText); + + var instance = binding.factory(el, data); + $(el).data("crosstalk-instance", instance); + $(el).addClass("crosstalk-input-bound"); +} + +if (global.Shiny) { + var inputBinding = new global.Shiny.InputBinding(); + var _$ = global.jQuery; + _$.extend(inputBinding, { + find: function find(scope) { + return _$(scope).find(".crosstalk-input"); + }, + initialize: function initialize(el) { + if (!_$(el).hasClass("crosstalk-input-bound")) { + bindEl(el); + } + }, + getId: function getId(el) { + return el.id; + }, + getValue: function getValue(el) {}, + setValue: function setValue(el, value) {}, + receiveMessage: function receiveMessage(el, data) {}, + subscribe: function subscribe(el, callback) { + _$(el).data("crosstalk-instance").resume(); + }, + unsubscribe: function unsubscribe(el) { + _$(el).data("crosstalk-instance").suspend(); + } + }); + global.Shiny.inputBindings.register(inputBinding, "crosstalk.inputBinding"); +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{}],7:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-checkboxgroup", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + var $el = $(el); + $el.on("change", "input[type='checkbox']", function () { + var checked = $el.find("input[type='checkbox']:checked"); + if (checked.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + checked.each(function () { + data.map[this.value].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],8:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; + +input.register({ + className: "crosstalk-input-select", + + factory: function factory(el, data) { + /* + * items: {value: [...], label: [...]} + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + + var first = [{ value: "", label: "(All)" }]; + var items = util.dataframeToD3(data.items); + var opts = { + options: first.concat(items), + valueField: "value", + labelField: "label", + searchField: "label" + }; + + var select = $(el).find("select")[0]; + + var selectize = $(select).selectize(opts)[0].selectize; + + var ctHandle = new _filter.FilterHandle(data.group); + + var lastKnownKeys = void 0; + selectize.on("change", function () { + if (selectize.items.length === 0) { + lastKnownKeys = null; + ctHandle.clear(); + } else { + var keys = {}; + selectize.items.forEach(function (group) { + data.map[group].forEach(function (key) { + keys[key] = true; + }); + }); + var keyArray = Object.keys(keys); + keyArray.sort(); + lastKnownKeys = keyArray; + ctHandle.set(keyArray); + } + }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6,"./util":11}],9:[function(require,module,exports){ +(function (global){ +"use strict"; + +var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); + +var _input = require("./input"); + +var input = _interopRequireWildcard(_input); + +var _filter = require("./filter"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var $ = global.jQuery; +var strftime = global.strftime; + +input.register({ + className: "crosstalk-input-slider", + + factory: function factory(el, data) { + /* + * map: {"groupA": ["keyA", "keyB", ...], ...} + * group: "ct-groupname" + */ + var ctHandle = new _filter.FilterHandle(data.group); + + var opts = {}; + var $el = $(el).find("input"); + var dataType = $el.data("data-type"); + var timeFormat = $el.data("time-format"); + var round = $el.data("round"); + var timeFormatter = void 0; + + // Set up formatting functions + if (dataType === "date") { + timeFormatter = strftime.utc(); + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "datetime") { + var timezone = $el.data("timezone"); + if (timezone) timeFormatter = strftime.timezone(timezone);else timeFormatter = strftime; + + opts.prettify = function (num) { + return timeFormatter(timeFormat, new Date(num)); + }; + } else if (dataType === "number") { + if (typeof round !== "undefined") opts.prettify = function (num) { + var factor = Math.pow(10, round); + return Math.round(num * factor) / factor; + }; + } + + $el.ionRangeSlider(opts); + + function getValue() { + var result = $el.data("ionRangeSlider").result; + + // Function for converting numeric value from slider to appropriate type. + var convert = void 0; + var dataType = $el.data("data-type"); + if (dataType === "date") { + convert = function convert(val) { + return formatDateUTC(new Date(+val)); + }; + } else if (dataType === "datetime") { + convert = function convert(val) { + // Convert ms to s + return +val / 1000; + }; + } else { + convert = function convert(val) { + return +val; + }; + } + + if ($el.data("ionRangeSlider").options.type === "double") { + return [convert(result.from), convert(result.to)]; + } else { + return convert(result.from); + } + } + + var lastKnownKeys = null; + + $el.on("change.crosstalkSliderInput", function (event) { + if (!$el.data("updating") && !$el.data("animating")) { + var _getValue = getValue(), + _getValue2 = _slicedToArray(_getValue, 2), + from = _getValue2[0], + to = _getValue2[1]; + + var keys = []; + for (var i = 0; i < data.values.length; i++) { + var val = data.values[i]; + if (val >= from && val <= to) { + keys.push(data.keys[i]); + } + } + keys.sort(); + ctHandle.set(keys); + lastKnownKeys = keys; + } + }); + + // let $el = $(el); + // $el.on("change", "input[type="checkbox"]", function() { + // let checked = $el.find("input[type="checkbox"]:checked"); + // if (checked.length === 0) { + // ctHandle.clear(); + // } else { + // let keys = {}; + // checked.each(function() { + // data.map[this.value].forEach(function(key) { + // keys[key] = true; + // }); + // }); + // let keyArray = Object.keys(keys); + // keyArray.sort(); + // ctHandle.set(keyArray); + // } + // }); + + return { + suspend: function suspend() { + ctHandle.clear(); + }, + resume: function resume() { + if (lastKnownKeys) ctHandle.set(lastKnownKeys); + } + }; + } +}); + +// Convert a number to a string with leading zeros +function padZeros(n, digits) { + var str = n.toString(); + while (str.length < digits) { + str = "0" + str; + }return str; +} + +// Given a Date object, return a string in yyyy-mm-dd format, using the +// UTC date. This may be a day off from the date in the local time zone. +function formatDateUTC(date) { + if (date instanceof Date) { + return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2); + } else { + return null; + } +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./filter":2,"./input":6}],10:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SelectionHandle = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +var _group = require("./group"); + +var _group2 = _interopRequireDefault(_group); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Use this class to read and write (and listen for changes to) the selection + * for a Crosstalk group. This is intended to be used for linked brushing. + * + * If two (or more) `SelectionHandle` instances in the same webpage share the + * same group name, they will share the same state. Setting the selection using + * one `SelectionHandle` instance will result in the `value` property instantly + * changing across the others, and `"change"` event listeners on all instances + * (including the one that initiated the sending) will fire. + * + * @param {string} [group] - The name of the Crosstalk group, or if none, + * null or undefined (or any other falsy value). This can be changed later + * via the [SelectionHandle#setGroup](#setGroup) method. + * @param {Object} [extraInfo] - An object whose properties will be copied to + * the event object whenever an event is emitted. + */ +var SelectionHandle = exports.SelectionHandle = function () { + function SelectionHandle() { + var group = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var extraInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, SelectionHandle); + + this._eventRelay = new _events2.default(); + this._emitter = new util.SubscriptionTracker(this._eventRelay); + + // Name of the group we're currently tracking, if any. Can change over time. + this._group = null; + // The Var we're currently tracking, if any. Can change over time. + this._var = null; + // The event handler subscription we currently have on var.on("change"). + this._varOnChangeSub = null; + + this._extraInfo = util.extend({ sender: this }, extraInfo); + + this.setGroup(group); + } + + /** + * Changes the Crosstalk group membership of this SelectionHandle. The group + * being switched away from (if any) will not have its selection value + * modified as a result of calling `setGroup`, even if this handle was the + * most recent handle to set the selection of the group. + * + * The group being switched to (if any) will also not have its selection value + * modified as a result of calling `setGroup`. If you want to set the + * selection value of the new group, call `set` explicitly. + * + * @param {string} group - The name of the Crosstalk group, or null (or + * undefined) to clear the group. + */ + + + _createClass(SelectionHandle, [{ + key: "setGroup", + value: function setGroup(group) { + var _this = this; + + // If group is unchanged, do nothing + if (this._group === group) return; + // Treat null, undefined, and other falsy values the same + if (!this._group && !group) return; + + if (this._var) { + this._var.off("change", this._varOnChangeSub); + this._var = null; + this._varOnChangeSub = null; + } + + this._group = group; + + if (group) { + this._var = (0, _group2.default)(group).var("selection"); + var sub = this._var.on("change", function (e) { + _this._eventRelay.trigger("change", e, _this); + }); + this._varOnChangeSub = sub; + } + } + + /** + * Retrieves the current selection for the group represented by this + * `SelectionHandle`. + * + * - If no selection is active, then this value will be falsy. + * - If a selection is active, but no data points are selected, then this + * value will be an empty array. + * - If a selection is active, and data points are selected, then the keys + * of the selected data points will be present in the array. + */ + + }, { + key: "_mergeExtraInfo", + + + /** + * Combines the given `extraInfo` (if any) with the handle's default + * `_extraInfo` (if any). + * @private + */ + value: function _mergeExtraInfo(extraInfo) { + // Important incidental effect: shallow clone is returned + return util.extend({}, this._extraInfo ? this._extraInfo : null, extraInfo ? extraInfo : null); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see + * {@link SelectionHandle#value}). + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any options that were + * passed into the `SelectionHandle` constructor). + */ + + }, { + key: "set", + value: function set(selectedKeys, extraInfo) { + if (this._var) this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo)); + } + + /** + * Overwrites the current selection for the group, and raises the `"change"` + * event among all of the group's '`SelectionHandle` instances (including + * this one). + * + * @fires SelectionHandle#change + * @param {Object} [extraInfo] - Extra properties to be included on the event + * object that's passed to listeners (in addition to any that were passed + * into the `SelectionHandle` constructor). + */ + + }, { + key: "clear", + value: function clear(extraInfo) { + if (this._var) this.set(void 0, this._mergeExtraInfo(extraInfo)); + } + + /** + * Subscribes to events on this `SelectionHandle`. + * + * @param {string} eventType - Indicates the type of events to listen to. + * Currently, only `"change"` is supported. + * @param {SelectionHandle~listener} listener - The callback function that + * will be invoked when the event occurs. + * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel + * this subscription. + */ + + }, { + key: "on", + value: function on(eventType, listener) { + return this._emitter.on(eventType, listener); + } + + /** + * Cancels event subscriptions created by {@link SelectionHandle#on}. + * + * @param {string} eventType - The type of event to unsubscribe. + * @param {string|SelectionHandle~listener} listener - Either the callback + * function previously passed into {@link SelectionHandle#on}, or the + * string that was returned from {@link SelectionHandle#on}. + */ + + }, { + key: "off", + value: function off(eventType, listener) { + return this._emitter.off(eventType, listener); + } + + /** + * Shuts down the `SelectionHandle` object. + * + * Removes all event listeners that were added through this handle. + */ + + }, { + key: "close", + value: function close() { + this._emitter.removeAllListeners(); + this.setGroup(null); + } + }, { + key: "value", + get: function get() { + return this._var ? this._var.get() : null; + } + }]); + + return SelectionHandle; +}(); + +/** + * @callback SelectionHandle~listener + * @param {Object} event - An object containing details of the event. For + * `"change"` events, this includes the properties `value` (the new + * value of the selection, or `undefined` if no selection is active), + * `oldValue` (the previous value of the selection), and `sender` (the + * `SelectionHandle` instance that made the change). + */ + +/** + * @event SelectionHandle#change + * @type {object} + * @property {object} value - The new value of the selection, or `undefined` + * if no selection is active. + * @property {object} oldValue - The previous value of the selection. + * @property {SelectionHandle} sender - The `SelectionHandle` instance that + * changed the value. + */ + +},{"./events":1,"./group":4,"./util":11}],11:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extend = extend; +exports.checkSorted = checkSorted; +exports.diffSortedLists = diffSortedLists; +exports.dataframeToD3 = dataframeToD3; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function extend(target) { + for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + sources[_key - 1] = arguments[_key]; + } + + for (var i = 0; i < sources.length; i++) { + var src = sources[i]; + if (typeof src === "undefined" || src === null) continue; + + for (var key in src) { + if (src.hasOwnProperty(key)) { + target[key] = src[key]; + } + } + } + return target; +} + +function checkSorted(list) { + for (var i = 1; i < list.length; i++) { + if (list[i] <= list[i - 1]) { + throw new Error("List is not sorted or contains duplicate"); + } + } +} + +function diffSortedLists(a, b) { + var i_a = 0; + var i_b = 0; + + if (!a) a = []; + if (!b) b = []; + + var a_only = []; + var b_only = []; + + checkSorted(a); + checkSorted(b); + + while (i_a < a.length && i_b < b.length) { + if (a[i_a] === b[i_b]) { + i_a++; + i_b++; + } else if (a[i_a] < b[i_b]) { + a_only.push(a[i_a++]); + } else { + b_only.push(b[i_b++]); + } + } + + if (i_a < a.length) a_only = a_only.concat(a.slice(i_a)); + if (i_b < b.length) b_only = b_only.concat(b.slice(i_b)); + return { + removed: a_only, + added: b_only + }; +} + +// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... } +// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ] +function dataframeToD3(df) { + var names = []; + var length = void 0; + for (var name in df) { + if (df.hasOwnProperty(name)) names.push(name); + if (_typeof(df[name]) !== "object" || typeof df[name].length === "undefined") { + throw new Error("All fields must be arrays"); + } else if (typeof length !== "undefined" && length !== df[name].length) { + throw new Error("All fields must be arrays of the same length"); + } + length = df[name].length; + } + var results = []; + var item = void 0; + for (var row = 0; row < length; row++) { + item = {}; + for (var col = 0; col < names.length; col++) { + item[names[col]] = df[names[col]][row]; + } + results.push(item); + } + return results; +} + +/** + * Keeps track of all event listener additions/removals and lets all active + * listeners be removed with a single operation. + * + * @private + */ + +var SubscriptionTracker = exports.SubscriptionTracker = function () { + function SubscriptionTracker(emitter) { + _classCallCheck(this, SubscriptionTracker); + + this._emitter = emitter; + this._subs = {}; + } + + _createClass(SubscriptionTracker, [{ + key: "on", + value: function on(eventType, listener) { + var sub = this._emitter.on(eventType, listener); + this._subs[sub] = eventType; + return sub; + } + }, { + key: "off", + value: function off(eventType, listener) { + var sub = this._emitter.off(eventType, listener); + if (sub) { + delete this._subs[sub]; + } + return sub; + } + }, { + key: "removeAllListeners", + value: function removeAllListeners() { + var _this = this; + + var current_subs = this._subs; + this._subs = {}; + Object.keys(current_subs).forEach(function (sub) { + _this._emitter.off(current_subs[sub], sub); + }); + } + }]); + + return SubscriptionTracker; +}(); + +},{}],12:[function(require,module,exports){ +(function (global){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _events = require("./events"); + +var _events2 = _interopRequireDefault(_events); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Var = function () { + function Var(group, name, /*optional*/value) { + _classCallCheck(this, Var); + + this._group = group; + this._name = name; + this._value = value; + this._events = new _events2.default(); + } + + _createClass(Var, [{ + key: "get", + value: function get() { + return this._value; + } + }, { + key: "set", + value: function set(value, /*optional*/event) { + if (this._value === value) { + // Do nothing; the value hasn't changed + return; + } + var oldValue = this._value; + this._value = value; + // Alert JavaScript listeners that the value has changed + var evt = {}; + if (event && (typeof event === "undefined" ? "undefined" : _typeof(event)) === "object") { + for (var k in event) { + if (event.hasOwnProperty(k)) evt[k] = event[k]; + } + } + evt.oldValue = oldValue; + evt.value = value; + this._events.trigger("change", evt, this); + + // TODO: Make this extensible, to let arbitrary back-ends know that + // something has changed + if (global.Shiny && global.Shiny.onInputChange) { + global.Shiny.onInputChange(".clientValue-" + (this._group.name !== null ? this._group.name + "-" : "") + this._name, typeof value === "undefined" ? null : value); + } + } + }, { + key: "on", + value: function on(eventType, listener) { + return this._events.on(eventType, listener); + } + }, { + key: "off", + value: function off(eventType, listener) { + return this._events.off(eventType, listener); + } + }]); + + return Var; +}(); + +exports.default = Var; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"./events":1}]},{},[5]) +//# sourceMappingURL=crosstalk.js.map diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js.map b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js.map new file mode 100644 index 0000000..cff94f0 --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.js.map @@ -0,0 +1,37 @@ +{ + "version": 3, + "sources": [ + "node_modules/browser-pack/_prelude.js", + "javascript/src/events.js", + "javascript/src/filter.js", + "javascript/src/filterset.js", + "javascript/src/group.js", + "javascript/src/index.js", + "javascript/src/input.js", + "javascript/src/input_checkboxgroup.js", + "javascript/src/input_selectize.js", + "javascript/src/input_slider.js", + "javascript/src/selection.js", + "javascript/src/util.js", + "javascript/src/var.js" + ], + "names": [], + "mappings": "AAAA;;;;;;;;;;;ICAqB,M;AACnB,oBAAc;AAAA;;AACZ,SAAK,MAAL,GAAc,EAAd;AACA,SAAK,IAAL,GAAY,CAAZ;AACD;;;;uBAEE,S,EAAW,Q,EAAU;AACtB,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,UAAI,CAAC,IAAL,EAAW;AACT,eAAO,KAAK,MAAL,CAAY,SAAZ,IAAyB,EAAhC;AACD;AACD,UAAI,MAAM,QAAS,KAAK,IAAL,EAAnB;AACA,WAAK,GAAL,IAAY,QAAZ;AACA,aAAO,GAAP;AACD;;AAED;;;;wBACI,S,EAAW,Q,EAAU;AACvB,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,UAAI,OAAO,QAAP,KAAqB,UAAzB,EAAqC;AACnC,aAAK,IAAI,GAAT,IAAgB,IAAhB,EAAsB;AACpB,cAAI,KAAK,cAAL,CAAoB,GAApB,CAAJ,EAA8B;AAC5B,gBAAI,KAAK,GAAL,MAAc,QAAlB,EAA4B;AAC1B,qBAAO,KAAK,GAAL,CAAP;AACA,qBAAO,GAAP;AACD;AACF;AACF;AACD,eAAO,KAAP;AACD,OAVD,MAUO,IAAI,OAAO,QAAP,KAAqB,QAAzB,EAAmC;AACxC,YAAI,QAAQ,KAAK,QAAL,CAAZ,EAA4B;AAC1B,iBAAO,KAAK,QAAL,CAAP;AACA,iBAAO,QAAP;AACD;AACD,eAAO,KAAP;AACD,OANM,MAMA;AACL,cAAM,IAAI,KAAJ,CAAU,8BAAV,CAAN;AACD;AACF;;;4BAEO,S,EAAW,G,EAAK,O,EAAS;AAC/B,UAAI,OAAO,KAAK,MAAL,CAAY,SAAZ,CAAX;AACA,WAAK,IAAI,GAAT,IAAgB,IAAhB,EAAsB;AACpB,YAAI,KAAK,cAAL,CAAoB,GAApB,CAAJ,EAA8B;AAC5B,eAAK,GAAL,EAAU,IAAV,CAAe,OAAf,EAAwB,GAAxB;AACD;AACF;AACF;;;;;;kBA/CkB,M;;;;;;;;;;;;ACArB;;;;AACA;;;;AACA;;;;AACA;;IAAY,I;;;;;;;;AAEZ,SAAS,YAAT,CAAsB,KAAtB,EAA6B;AAC3B,MAAI,QAAQ,MAAM,GAAN,CAAU,WAAV,CAAZ;AACA,MAAI,SAAS,MAAM,GAAN,EAAb;AACA,MAAI,CAAC,MAAL,EAAa;AACX,aAAS,yBAAT;AACA,UAAM,GAAN,CAAU,MAAV;AACD;AACD,SAAO,MAAP;AACD;;AAED,IAAI,KAAK,CAAT;AACA,SAAS,MAAT,GAAkB;AAChB,SAAO,IAAP;AACD;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;IAwBa,Y,WAAA,Y;AACX,wBAAY,KAAZ,EAAmB,SAAnB,EAA8B;AAAA;;AAC5B,SAAK,WAAL,GAAmB,sBAAnB;AACA,SAAK,QAAL,GAAgB,IAAI,KAAK,mBAAT,CAA6B,KAAK,WAAlC,CAAhB;;AAEA;AACA,SAAK,MAAL,GAAc,IAAd;AACA;AACA,SAAK,UAAL,GAAkB,IAAlB;AACA;AACA,SAAK,UAAL,GAAkB,IAAlB;AACA;AACA,SAAK,eAAL,GAAuB,IAAvB;;AAEA,SAAK,UAAL,GAAkB,KAAK,MAAL,CAAY,EAAE,QAAQ,IAAV,EAAZ,EAA8B,SAA9B,CAAlB;;AAEA,SAAK,GAAL,GAAW,WAAW,QAAtB;;AAEA,SAAK,QAAL,CAAc,KAAd;AACD;;AAED;;;;;;;;;;;;;;6BAUS,K,EAAO;AAAA;;AACd;AACA,UAAI,KAAK,MAAL,KAAgB,KAApB,EACE;AACF;AACA,UAAI,CAAC,KAAK,MAAN,IAAgB,CAAC,KAArB,EACE;;AAEF,UAAI,KAAK,UAAT,EAAqB;AACnB,aAAK,UAAL,CAAgB,GAAhB,CAAoB,QAApB,EAA8B,KAAK,eAAnC;AACA,aAAK,KAAL;AACA,aAAK,eAAL,GAAuB,IAAvB;AACA,aAAK,UAAL,GAAkB,IAAlB;AACA,aAAK,UAAL,GAAkB,IAAlB;AACD;;AAED,WAAK,MAAL,GAAc,KAAd;;AAEA,UAAI,KAAJ,EAAW;AACT,gBAAQ,qBAAI,KAAJ,CAAR;AACA,aAAK,UAAL,GAAkB,aAAa,KAAb,CAAlB;AACA,aAAK,UAAL,GAAkB,qBAAI,KAAJ,EAAW,GAAX,CAAe,QAAf,CAAlB;AACA,YAAI,MAAM,KAAK,UAAL,CAAgB,EAAhB,CAAmB,QAAnB,EAA6B,UAAC,CAAD,EAAO;AAC5C,gBAAK,WAAL,CAAiB,OAAjB,CAAyB,QAAzB,EAAmC,CAAnC;AACD,SAFS,CAAV;AAGA,aAAK,eAAL,GAAuB,GAAvB;AACD;AACF;;AAED;;;;;;;;oCAKgB,S,EAAW;AACzB,aAAO,KAAK,MAAL,CAAY,EAAZ,EACL,KAAK,UAAL,GAAkB,KAAK,UAAvB,GAAoC,IAD/B,EAEL,YAAY,SAAZ,GAAwB,IAFnB,CAAP;AAGD;;AAED;;;;;;;4BAIQ;AACN,WAAK,QAAL,CAAc,kBAAd;AACA,WAAK,KAAL;AACA,WAAK,QAAL,CAAc,IAAd;AACD;;AAED;;;;;;;;;;;;0BASM,S,EAAW;AACf,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,KAAhB,CAAsB,KAAK,GAA3B;AACA,WAAK,SAAL,CAAe,SAAf;AACD;;AAED;;;;;;;;;;;;;;;;;;;;wBAiBI,I,EAAM,S,EAAW;AACnB,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,MAAhB,CAAuB,KAAK,GAA5B,EAAiC,IAAjC;AACA,WAAK,SAAL,CAAe,SAAf;AACD;;AAED;;;;;;;;;;AASA;;;;;;;;;;uBAUG,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;AAED;;;;;;;;;;;wBAQI,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAP;AACD;;;8BAES,S,EAAW;AACnB,UAAI,CAAC,KAAK,UAAV,EACE;AACF,WAAK,UAAL,CAAgB,GAAhB,CAAoB,KAAK,UAAL,CAAgB,KAApC,EAA2C,KAAK,eAAL,CAAqB,SAArB,CAA3C;AACD;;AAED;;;;;;;;;;;wBApCmB;AACjB,aAAO,KAAK,UAAL,GAAkB,KAAK,UAAL,CAAgB,KAAlC,GAA0C,IAAjD;AACD;;;;;;AA6CH;;;;;;;;;;;;;;;;;;;ACzNA;;;;AAEA,SAAS,iBAAT,CAA2B,CAA3B,EAA8B,CAA9B,EAAiC;AAC/B,MAAI,MAAM,CAAV,EAAa;AACX,WAAO,CAAP;AACD,GAFD,MAEO,IAAI,IAAI,CAAR,EAAW;AAChB,WAAO,CAAC,CAAR;AACD,GAFM,MAEA,IAAI,IAAI,CAAR,EAAW;AAChB,WAAO,CAAP;AACD;AACF;;AAED;;;;IAGqB,S;AACnB,uBAAc;AAAA;;AACZ,SAAK,KAAL;AACD;;;;4BAEO;AACN;AACA,WAAK,QAAL,GAAgB,EAAhB;AACA;AACA,WAAK,KAAL,GAAa,EAAb;AACA,WAAK,MAAL,GAAc,IAAd;AACA,WAAK,cAAL,GAAsB,CAAtB;AACD;;;2BAMM,Q,EAAU,I,EAAM;AACrB,UAAI,SAAS,IAAb,EAAmB;AACjB,eAAO,KAAK,KAAL,CAAW,CAAX,CAAP,CADiB,CACK;AACtB,aAAK,IAAL,CAAU,iBAAV;AACD;;AAJoB,6BAME,2BAAgB,KAAK,QAAL,CAAc,QAAd,CAAhB,EAAyC,IAAzC,CANF;AAAA,UAMhB,KANgB,oBAMhB,KANgB;AAAA,UAMT,OANS,oBAMT,OANS;;AAOrB,WAAK,QAAL,CAAc,QAAd,IAA0B,IAA1B;;AAEA,WAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,MAAM,MAA1B,EAAkC,GAAlC,EAAuC;AACrC,aAAK,KAAL,CAAW,MAAM,CAAN,CAAX,IAAuB,CAAC,KAAK,KAAL,CAAW,MAAM,CAAN,CAAX,KAAwB,CAAzB,IAA8B,CAArD;AACD;AACD,WAAK,IAAI,KAAI,CAAb,EAAgB,KAAI,QAAQ,MAA5B,EAAoC,IAApC,EAAyC;AACvC,aAAK,KAAL,CAAW,QAAQ,EAAR,CAAX;AACD;;AAED,WAAK,YAAL,CAAkB,IAAlB;AACD;;AAED;;;;;;;;mCAKmC;AAAA,UAAtB,IAAsB,uEAAf,KAAK,QAAU;;AACjC,UAAI,cAAc,OAAO,IAAP,CAAY,KAAK,QAAjB,EAA2B,MAA7C;AACA,UAAI,gBAAgB,CAApB,EAAuB;AACrB,aAAK,MAAL,GAAc,IAAd;AACD,OAFD,MAEO;AACL,aAAK,MAAL,GAAc,EAAd;AACA,aAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,cAAI,QAAQ,KAAK,KAAL,CAAW,KAAK,CAAL,CAAX,CAAZ;AACA,cAAI,UAAU,WAAd,EAA2B;AACzB,iBAAK,MAAL,CAAY,IAAZ,CAAiB,KAAK,CAAL,CAAjB;AACD;AACF;AACF;AACF;;;0BAEK,Q,EAAU;AACd,UAAI,OAAO,KAAK,QAAL,CAAc,QAAd,CAAP,KAAoC,WAAxC,EAAqD;AACnD;AACD;;AAED,UAAI,OAAO,KAAK,QAAL,CAAc,QAAd,CAAX;AACA,UAAI,CAAC,IAAL,EAAW;AACT,eAAO,EAAP;AACD;;AAED,WAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,aAAK,KAAL,CAAW,KAAK,CAAL,CAAX;AACD;AACD,aAAO,KAAK,QAAL,CAAc,QAAd,CAAP;;AAEA,WAAK,YAAL;AACD;;;wBA3DW;AACV,aAAO,KAAK,MAAZ;AACD;;;wBA2Dc;AACb,UAAI,UAAU,OAAO,IAAP,CAAY,KAAK,KAAjB,CAAd;AACA,cAAQ,IAAR,CAAa,iBAAb;AACA,aAAO,OAAP;AACD;;;;;;kBA/EkB,S;;;;;;;;;;;;;;kBCRG,K;;AAPxB;;;;;;;;AAEA;AACA;AACA,OAAO,kBAAP,GAA4B,OAAO,kBAAP,IAA6B,EAAzD;AACA,IAAI,SAAS,OAAO,kBAApB;;AAEe,SAAS,KAAT,CAAe,SAAf,EAA0B;AACvC,MAAI,aAAa,OAAO,SAAP,KAAsB,QAAvC,EAAiD;AAC/C,QAAI,CAAC,OAAO,cAAP,CAAsB,SAAtB,CAAL,EAAuC;AACrC,aAAO,SAAP,IAAoB,IAAI,KAAJ,CAAU,SAAV,CAApB;AACD;AACD,WAAO,OAAO,SAAP,CAAP;AACD,GALD,MAKO,IAAI,QAAO,SAAP,yCAAO,SAAP,OAAsB,QAAtB,IAAkC,UAAU,KAA5C,IAAqD,UAAU,GAAnE,EAAwE;AAC7E;AACA,WAAO,SAAP;AACD,GAHM,MAGA,IAAI,MAAM,OAAN,CAAc,SAAd,KACP,UAAU,MAAV,IAAoB,CADb,IAEP,OAAO,UAAU,CAAV,CAAP,KAAyB,QAFtB,EAEgC;AACrC,WAAO,MAAM,UAAU,CAAV,CAAN,CAAP;AACD,GAJM,MAIA;AACL,UAAM,IAAI,KAAJ,CAAU,4BAAV,CAAN;AACD;AACF;;IAEK,K;AACJ,iBAAY,IAAZ,EAAkB;AAAA;;AAChB,SAAK,IAAL,GAAY,IAAZ;AACA,SAAK,KAAL,GAAa,EAAb;AACD;;;;yBAEG,I,EAAM;AACR,UAAI,CAAC,IAAD,IAAS,OAAO,IAAP,KAAiB,QAA9B,EAAwC;AACtC,cAAM,IAAI,KAAJ,CAAU,kBAAV,CAAN;AACD;;AAED,UAAI,CAAC,KAAK,KAAL,CAAW,cAAX,CAA0B,IAA1B,CAAL,EACE,KAAK,KAAL,CAAW,IAAX,IAAmB,kBAAQ,IAAR,EAAc,IAAd,CAAnB;AACF,aAAO,KAAK,KAAL,CAAW,IAAX,CAAP;AACD;;;wBAEG,I,EAAM;AACR,UAAI,CAAC,IAAD,IAAS,OAAO,IAAP,KAAiB,QAA9B,EAAwC;AACtC,cAAM,IAAI,KAAJ,CAAU,kBAAV,CAAN;AACD;;AAED,aAAO,KAAK,KAAL,CAAW,cAAX,CAA0B,IAA1B,CAAP;AACD;;;;;;;;;;;;;;;;AC/CH;;;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEA,IAAM,eAAe,qBAAM,SAAN,CAArB;;AAEA,SAAS,IAAT,CAAc,IAAd,EAAoB;AAClB,SAAO,aAAa,GAAb,CAAiB,IAAjB,CAAP;AACD;;AAED,SAAS,GAAT,CAAa,IAAb,EAAmB;AACjB,SAAO,aAAa,GAAb,CAAiB,IAAjB,CAAP;AACD;;AAED,IAAI,OAAO,KAAX,EAAkB;AAChB,SAAO,KAAP,CAAa,uBAAb,CAAqC,qBAArC,EAA4D,UAAS,OAAT,EAAkB;AAC5E,QAAI,OAAO,QAAQ,KAAf,KAA0B,QAA9B,EAAwC;AACtC,2BAAM,QAAQ,KAAd,EAAqB,GAArB,CAAyB,QAAQ,IAAjC,EAAuC,GAAvC,CAA2C,QAAQ,KAAnD;AACD,KAFD,MAEO;AACL,WAAK,QAAQ,IAAb,EAAmB,GAAnB,CAAuB,QAAQ,KAA/B;AACD;AACF,GAND;AAOD;;AAED,IAAM,YAAY;AAChB,wBADgB;AAEhB,OAAK,IAFW;AAGhB,OAAK,GAHW;AAIhB,6CAJgB;AAKhB,oCALgB;AAMhB;AANgB,CAAlB;;AASA;;;kBAGe,S;;AACf,OAAO,SAAP,GAAmB,SAAnB;;;;;;;;;;;QCrCgB,Q,GAAA,Q;QAWA,I,GAAA,I;AAfhB,IAAI,IAAI,OAAO,MAAf;;AAEA,IAAI,WAAW,EAAf;;AAEO,SAAS,QAAT,CAAkB,GAAlB,EAAuB;AAC5B,WAAS,IAAI,SAAb,IAA0B,GAA1B;AACA,MAAI,OAAO,QAAP,IAAmB,OAAO,QAAP,CAAgB,UAAhB,KAA+B,UAAtD,EAAkE;AAChE,MAAE,YAAM;AACN;AACD,KAFD;AAGD,GAJD,MAIO,IAAI,OAAO,QAAX,EAAqB;AAC1B,eAAW,IAAX,EAAiB,GAAjB;AACD;AACF;;AAEM,SAAS,IAAT,GAAgB;AACrB,SAAO,IAAP,CAAY,QAAZ,EAAsB,OAAtB,CAA8B,UAAS,SAAT,EAAoB;AAChD,QAAI,UAAU,SAAS,SAAT,CAAd;AACA,MAAE,MAAM,QAAQ,SAAhB,EAA2B,GAA3B,CAA+B,wBAA/B,EAAyD,IAAzD,CAA8D,UAAS,CAAT,EAAY,EAAZ,EAAgB;AAC5E,mBAAa,OAAb,EAAsB,EAAtB;AACD,KAFD;AAGD,GALD;AAMD;;AAED;AACA,SAAS,OAAT,CAAiB,GAAjB,EAAsB;AACpB,SAAO,IAAI,OAAJ,CAAY,uCAAZ,EAAqD,MAArD,CAAP;AACD;;AAED,SAAS,MAAT,CAAgB,EAAhB,EAAoB;AAClB,MAAI,MAAM,EAAE,EAAF,CAAV;AACA,SAAO,IAAP,CAAY,QAAZ,EAAsB,OAAtB,CAA8B,UAAS,SAAT,EAAoB;AAChD,QAAI,IAAI,QAAJ,CAAa,SAAb,KAA2B,CAAC,IAAI,QAAJ,CAAa,uBAAb,CAAhC,EAAuE;AACrE,UAAI,UAAU,SAAS,SAAT,CAAd;AACA,mBAAa,OAAb,EAAsB,EAAtB;AACD;AACF,GALD;AAMD;;AAED,SAAS,YAAT,CAAsB,OAAtB,EAA+B,EAA/B,EAAmC;AACjC,MAAI,SAAS,EAAE,EAAF,EAAM,IAAN,CAAW,+CAA+C,QAAQ,GAAG,EAAX,CAA/C,GAAgE,IAA3E,CAAb;AACA,MAAI,OAAO,KAAK,KAAL,CAAW,OAAO,CAAP,EAAU,SAArB,CAAX;;AAEA,MAAI,WAAW,QAAQ,OAAR,CAAgB,EAAhB,EAAoB,IAApB,CAAf;AACA,IAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,QAAjC;AACA,IAAE,EAAF,EAAM,QAAN,CAAe,uBAAf;AACD;;AAED,IAAI,OAAO,KAAX,EAAkB;AAChB,MAAI,eAAe,IAAI,OAAO,KAAP,CAAa,YAAjB,EAAnB;AACA,MAAI,KAAI,OAAO,MAAf;AACA,KAAE,MAAF,CAAS,YAAT,EAAuB;AACrB,UAAM,cAAS,KAAT,EAAgB;AACpB,aAAO,GAAE,KAAF,EAAS,IAAT,CAAc,kBAAd,CAAP;AACD,KAHoB;AAIrB,gBAAY,oBAAS,EAAT,EAAa;AACvB,UAAI,CAAC,GAAE,EAAF,EAAM,QAAN,CAAe,uBAAf,CAAL,EAA8C;AAC5C,eAAO,EAAP;AACD;AACF,KARoB;AASrB,WAAO,eAAS,EAAT,EAAa;AAClB,aAAO,GAAG,EAAV;AACD,KAXoB;AAYrB,cAAU,kBAAS,EAAT,EAAa,CAEtB,CAdoB;AAerB,cAAU,kBAAS,EAAT,EAAa,KAAb,EAAoB,CAE7B,CAjBoB;AAkBrB,oBAAgB,wBAAS,EAAT,EAAa,IAAb,EAAmB,CAElC,CApBoB;AAqBrB,eAAW,mBAAS,EAAT,EAAa,QAAb,EAAuB;AAChC,SAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,MAAjC;AACD,KAvBoB;AAwBrB,iBAAa,qBAAS,EAAT,EAAa;AACxB,SAAE,EAAF,EAAM,IAAN,CAAW,oBAAX,EAAiC,OAAjC;AACD;AA1BoB,GAAvB;AA4BA,SAAO,KAAP,CAAa,aAAb,CAA2B,QAA3B,CAAoC,YAApC,EAAkD,wBAAlD;AACD;;;;;;;;AChFD;;IAAY,K;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,+BADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;AAIA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,sBAAJ;AACA,QAAI,MAAM,EAAE,EAAF,CAAV;AACA,QAAI,EAAJ,CAAO,QAAP,EAAiB,wBAAjB,EAA2C,YAAW;AACpD,UAAI,UAAU,IAAI,IAAJ,CAAS,gCAAT,CAAd;AACA,UAAI,QAAQ,MAAR,KAAmB,CAAvB,EAA0B;AACxB,wBAAgB,IAAhB;AACA,iBAAS,KAAT;AACD,OAHD,MAGO;AACL,YAAI,OAAO,EAAX;AACA,gBAAQ,IAAR,CAAa,YAAW;AACtB,eAAK,GAAL,CAAS,KAAK,KAAd,EAAqB,OAArB,CAA6B,UAAS,GAAT,EAAc;AACzC,iBAAK,GAAL,IAAY,IAAZ;AACD,WAFD;AAGD,SAJD;AAKA,YAAI,WAAW,OAAO,IAAP,CAAY,IAAZ,CAAf;AACA,iBAAS,IAAT;AACA,wBAAgB,QAAhB;AACA,iBAAS,GAAT,CAAa,QAAb;AACD;AACF,KAjBD;;AAmBA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AAxCY,CAAf;;;;;;;;ACLA;;IAAY,K;;AACZ;;IAAY,I;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,wBADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;;;AAMA,QAAI,QAAQ,CAAC,EAAC,OAAO,EAAR,EAAY,OAAO,OAAnB,EAAD,CAAZ;AACA,QAAI,QAAQ,KAAK,aAAL,CAAmB,KAAK,KAAxB,CAAZ;AACA,QAAI,OAAO;AACT,eAAS,MAAM,MAAN,CAAa,KAAb,CADA;AAET,kBAAY,OAFH;AAGT,kBAAY,OAHH;AAIT,mBAAa;AAJJ,KAAX;;AAOA,QAAI,SAAS,EAAE,EAAF,EAAM,IAAN,CAAW,QAAX,EAAqB,CAArB,CAAb;;AAEA,QAAI,YAAY,EAAE,MAAF,EAAU,SAAV,CAAoB,IAApB,EAA0B,CAA1B,EAA6B,SAA7C;;AAEA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,sBAAJ;AACA,cAAU,EAAV,CAAa,QAAb,EAAuB,YAAW;AAChC,UAAI,UAAU,KAAV,CAAgB,MAAhB,KAA2B,CAA/B,EAAkC;AAChC,wBAAgB,IAAhB;AACA,iBAAS,KAAT;AACD,OAHD,MAGO;AACL,YAAI,OAAO,EAAX;AACA,kBAAU,KAAV,CAAgB,OAAhB,CAAwB,UAAS,KAAT,EAAgB;AACtC,eAAK,GAAL,CAAS,KAAT,EAAgB,OAAhB,CAAwB,UAAS,GAAT,EAAc;AACpC,iBAAK,GAAL,IAAY,IAAZ;AACD,WAFD;AAGD,SAJD;AAKA,YAAI,WAAW,OAAO,IAAP,CAAY,IAAZ,CAAf;AACA,iBAAS,IAAT;AACA,wBAAgB,QAAhB;AACA,iBAAS,GAAT,CAAa,QAAb;AACD;AACF,KAhBD;;AAkBA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AArDY,CAAf;;;;;;;;;;ACNA;;IAAY,K;;AACZ;;;;AAEA,IAAI,IAAI,OAAO,MAAf;AACA,IAAI,WAAW,OAAO,QAAtB;;AAEA,MAAM,QAAN,CAAe;AACb,aAAW,wBADE;;AAGb,WAAS,iBAAS,EAAT,EAAa,IAAb,EAAmB;AAC1B;;;;AAIA,QAAI,WAAW,yBAAiB,KAAK,KAAtB,CAAf;;AAEA,QAAI,OAAO,EAAX;AACA,QAAI,MAAM,EAAE,EAAF,EAAM,IAAN,CAAW,OAAX,CAAV;AACA,QAAI,WAAW,IAAI,IAAJ,CAAS,WAAT,CAAf;AACA,QAAI,aAAa,IAAI,IAAJ,CAAS,aAAT,CAAjB;AACA,QAAI,QAAQ,IAAI,IAAJ,CAAS,OAAT,CAAZ;AACA,QAAI,sBAAJ;;AAEA;AACA,QAAI,aAAa,MAAjB,EAAyB;AACvB,sBAAgB,SAAS,GAAT,EAAhB;AACA,WAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,eAAO,cAAc,UAAd,EAA0B,IAAI,IAAJ,CAAS,GAAT,CAA1B,CAAP;AACD,OAFD;AAID,KAND,MAMO,IAAI,aAAa,UAAjB,EAA6B;AAClC,UAAI,WAAW,IAAI,IAAJ,CAAS,UAAT,CAAf;AACA,UAAI,QAAJ,EACE,gBAAgB,SAAS,QAAT,CAAkB,QAAlB,CAAhB,CADF,KAGE,gBAAgB,QAAhB;;AAEF,WAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,eAAO,cAAc,UAAd,EAA0B,IAAI,IAAJ,CAAS,GAAT,CAA1B,CAAP;AACD,OAFD;AAGD,KAVM,MAUA,IAAI,aAAa,QAAjB,EAA2B;AAChC,UAAI,OAAO,KAAP,KAAiB,WAArB,EACE,KAAK,QAAL,GAAgB,UAAS,GAAT,EAAc;AAC5B,YAAI,SAAS,KAAK,GAAL,CAAS,EAAT,EAAa,KAAb,CAAb;AACA,eAAO,KAAK,KAAL,CAAW,MAAM,MAAjB,IAA2B,MAAlC;AACD,OAHD;AAIH;;AAED,QAAI,cAAJ,CAAmB,IAAnB;;AAEA,aAAS,QAAT,GAAoB;AAClB,UAAI,SAAS,IAAI,IAAJ,CAAS,gBAAT,EAA2B,MAAxC;;AAEA;AACA,UAAI,gBAAJ;AACA,UAAI,WAAW,IAAI,IAAJ,CAAS,WAAT,CAAf;AACA,UAAI,aAAa,MAAjB,EAAyB;AACvB,kBAAU,iBAAS,GAAT,EAAc;AACtB,iBAAO,cAAc,IAAI,IAAJ,CAAS,CAAC,GAAV,CAAd,CAAP;AACD,SAFD;AAGD,OAJD,MAIO,IAAI,aAAa,UAAjB,EAA6B;AAClC,kBAAU,iBAAS,GAAT,EAAc;AACtB;AACA,iBAAO,CAAC,GAAD,GAAO,IAAd;AACD,SAHD;AAID,OALM,MAKA;AACL,kBAAU,iBAAS,GAAT,EAAc;AAAE,iBAAO,CAAC,GAAR;AAAc,SAAxC;AACD;;AAED,UAAI,IAAI,IAAJ,CAAS,gBAAT,EAA2B,OAA3B,CAAmC,IAAnC,KAA4C,QAAhD,EAA0D;AACxD,eAAO,CAAC,QAAQ,OAAO,IAAf,CAAD,EAAuB,QAAQ,OAAO,EAAf,CAAvB,CAAP;AACD,OAFD,MAEO;AACL,eAAO,QAAQ,OAAO,IAAf,CAAP;AACD;AACF;;AAED,QAAI,gBAAgB,IAApB;;AAEA,QAAI,EAAJ,CAAO,6BAAP,EAAsC,UAAS,KAAT,EAAgB;AACpD,UAAI,CAAC,IAAI,IAAJ,CAAS,UAAT,CAAD,IAAyB,CAAC,IAAI,IAAJ,CAAS,WAAT,CAA9B,EAAqD;AAAA,wBAClC,UADkC;AAAA;AAAA,YAC9C,IAD8C;AAAA,YACxC,EADwC;;AAEnD,YAAI,OAAO,EAAX;AACA,aAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAL,CAAY,MAAhC,EAAwC,GAAxC,EAA6C;AAC3C,cAAI,MAAM,KAAK,MAAL,CAAY,CAAZ,CAAV;AACA,cAAI,OAAO,IAAP,IAAe,OAAO,EAA1B,EAA8B;AAC5B,iBAAK,IAAL,CAAU,KAAK,IAAL,CAAU,CAAV,CAAV;AACD;AACF;AACD,aAAK,IAAL;AACA,iBAAS,GAAT,CAAa,IAAb;AACA,wBAAgB,IAAhB;AACD;AACF,KAdD;;AAiBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAO;AACL,eAAS,mBAAW;AAClB,iBAAS,KAAT;AACD,OAHI;AAIL,cAAQ,kBAAW;AACjB,YAAI,aAAJ,EACE,SAAS,GAAT,CAAa,aAAb;AACH;AAPI,KAAP;AASD;AApHY,CAAf;;AAwHA;AACA,SAAS,QAAT,CAAkB,CAAlB,EAAqB,MAArB,EAA6B;AAC3B,MAAI,MAAM,EAAE,QAAF,EAAV;AACA,SAAO,IAAI,MAAJ,GAAa,MAApB;AACE,UAAM,MAAM,GAAZ;AADF,GAEA,OAAO,GAAP;AACD;;AAED;AACA;AACA,SAAS,aAAT,CAAuB,IAAvB,EAA6B;AAC3B,MAAI,gBAAgB,IAApB,EAA0B;AACxB,WAAO,KAAK,cAAL,KAAwB,GAAxB,GACA,SAAS,KAAK,WAAL,KAAmB,CAA5B,EAA+B,CAA/B,CADA,GACoC,GADpC,GAEA,SAAS,KAAK,UAAL,EAAT,EAA4B,CAA5B,CAFP;AAID,GALD,MAKO;AACL,WAAO,IAAP;AACD;AACF;;;;;;;;;;;;;;ACjJD;;;;AACA;;;;AACA;;IAAY,I;;;;;;;;AAEZ;;;;;;;;;;;;;;;;IAgBa,e,WAAA,e;AAEX,6BAA4C;AAAA,QAAhC,KAAgC,uEAAxB,IAAwB;AAAA,QAAlB,SAAkB,uEAAN,IAAM;;AAAA;;AAC1C,SAAK,WAAL,GAAmB,sBAAnB;AACA,SAAK,QAAL,GAAgB,IAAI,KAAK,mBAAT,CAA6B,KAAK,WAAlC,CAAhB;;AAEA;AACA,SAAK,MAAL,GAAc,IAAd;AACA;AACA,SAAK,IAAL,GAAY,IAAZ;AACA;AACA,SAAK,eAAL,GAAuB,IAAvB;;AAEA,SAAK,UAAL,GAAkB,KAAK,MAAL,CAAY,EAAE,QAAQ,IAAV,EAAZ,EAA8B,SAA9B,CAAlB;;AAEA,SAAK,QAAL,CAAc,KAAd;AACD;;AAED;;;;;;;;;;;;;;;;;6BAaS,K,EAAO;AAAA;;AACd;AACA,UAAI,KAAK,MAAL,KAAgB,KAApB,EACE;AACF;AACA,UAAI,CAAC,KAAK,MAAN,IAAgB,CAAC,KAArB,EACE;;AAEF,UAAI,KAAK,IAAT,EAAe;AACb,aAAK,IAAL,CAAU,GAAV,CAAc,QAAd,EAAwB,KAAK,eAA7B;AACA,aAAK,IAAL,GAAY,IAAZ;AACA,aAAK,eAAL,GAAuB,IAAvB;AACD;;AAED,WAAK,MAAL,GAAc,KAAd;;AAEA,UAAI,KAAJ,EAAW;AACT,aAAK,IAAL,GAAY,qBAAI,KAAJ,EAAW,GAAX,CAAe,WAAf,CAAZ;AACA,YAAI,MAAM,KAAK,IAAL,CAAU,EAAV,CAAa,QAAb,EAAuB,UAAC,CAAD,EAAO;AACtC,gBAAK,WAAL,CAAiB,OAAjB,CAAyB,QAAzB,EAAmC,CAAnC;AACD,SAFS,CAAV;AAGA,aAAK,eAAL,GAAuB,GAAvB;AACD;AACF;;AAED;;;;;;;;;;;;;;;AAcA;;;;;oCAKgB,S,EAAW;AACzB;AACA,aAAO,KAAK,MAAL,CAAY,EAAZ,EACL,KAAK,UAAL,GAAkB,KAAK,UAAvB,GAAoC,IAD/B,EAEL,YAAY,SAAZ,GAAwB,IAFnB,CAAP;AAGD;;AAED;;;;;;;;;;;;;;;wBAYI,Y,EAAc,S,EAAW;AAC3B,UAAI,KAAK,IAAT,EACE,KAAK,IAAL,CAAU,GAAV,CAAc,YAAd,EAA4B,KAAK,eAAL,CAAqB,SAArB,CAA5B;AACH;;AAED;;;;;;;;;;;;;0BAUM,S,EAAW;AACf,UAAI,KAAK,IAAT,EACE,KAAK,GAAL,CAAS,KAAK,CAAd,EAAiB,KAAK,eAAL,CAAqB,SAArB,CAAjB;AACH;;AAED;;;;;;;;;;;;;uBAUG,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;AAED;;;;;;;;;;;wBAQI,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAP;AACD;;AAED;;;;;;;;4BAKQ;AACN,WAAK,QAAL,CAAc,kBAAd;AACA,WAAK,QAAL,CAAc,IAAd;AACD;;;wBAlFW;AACV,aAAO,KAAK,IAAL,GAAY,KAAK,IAAL,CAAU,GAAV,EAAZ,GAA8B,IAArC;AACD;;;;;;AAmFH;;;;;;;;;AASA;;;;;;;;;;;;;;;;;;;;;QCpLgB,M,GAAA,M;QAeA,W,GAAA,W;QAQA,e,GAAA,e;QAoCA,a,GAAA,a;;;;AA3DT,SAAS,MAAT,CAAgB,MAAhB,EAAoC;AAAA,oCAAT,OAAS;AAAT,WAAS;AAAA;;AACzC,OAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,QAAQ,MAA5B,EAAoC,GAApC,EAAyC;AACvC,QAAI,MAAM,QAAQ,CAAR,CAAV;AACA,QAAI,OAAO,GAAP,KAAgB,WAAhB,IAA+B,QAAQ,IAA3C,EACE;;AAEF,SAAK,IAAI,GAAT,IAAgB,GAAhB,EAAqB;AACnB,UAAI,IAAI,cAAJ,CAAmB,GAAnB,CAAJ,EAA6B;AAC3B,eAAO,GAAP,IAAc,IAAI,GAAJ,CAAd;AACD;AACF;AACF;AACD,SAAO,MAAP;AACD;;AAEM,SAAS,WAAT,CAAqB,IAArB,EAA2B;AAChC,OAAK,IAAI,IAAI,CAAb,EAAgB,IAAI,KAAK,MAAzB,EAAiC,GAAjC,EAAsC;AACpC,QAAI,KAAK,CAAL,KAAW,KAAK,IAAE,CAAP,CAAf,EAA0B;AACxB,YAAM,IAAI,KAAJ,CAAU,0CAAV,CAAN;AACD;AACF;AACF;;AAEM,SAAS,eAAT,CAAyB,CAAzB,EAA4B,CAA5B,EAA+B;AACpC,MAAI,MAAM,CAAV;AACA,MAAI,MAAM,CAAV;;AAEA,MAAI,CAAC,CAAL,EAAQ,IAAI,EAAJ;AACR,MAAI,CAAC,CAAL,EAAQ,IAAI,EAAJ;;AAER,MAAI,SAAS,EAAb;AACA,MAAI,SAAS,EAAb;;AAEA,cAAY,CAAZ;AACA,cAAY,CAAZ;;AAEA,SAAO,MAAM,EAAE,MAAR,IAAkB,MAAM,EAAE,MAAjC,EAAyC;AACvC,QAAI,EAAE,GAAF,MAAW,EAAE,GAAF,CAAf,EAAuB;AACrB;AACA;AACD,KAHD,MAGO,IAAI,EAAE,GAAF,IAAS,EAAE,GAAF,CAAb,EAAqB;AAC1B,aAAO,IAAP,CAAY,EAAE,KAAF,CAAZ;AACD,KAFM,MAEA;AACL,aAAO,IAAP,CAAY,EAAE,KAAF,CAAZ;AACD;AACF;;AAED,MAAI,MAAM,EAAE,MAAZ,EACE,SAAS,OAAO,MAAP,CAAc,EAAE,KAAF,CAAQ,GAAR,CAAd,CAAT;AACF,MAAI,MAAM,EAAE,MAAZ,EACE,SAAS,OAAO,MAAP,CAAc,EAAE,KAAF,CAAQ,GAAR,CAAd,CAAT;AACF,SAAO;AACL,aAAS,MADJ;AAEL,WAAO;AAFF,GAAP;AAID;;AAED;AACA;AACO,SAAS,aAAT,CAAuB,EAAvB,EAA2B;AAChC,MAAI,QAAQ,EAAZ;AACA,MAAI,eAAJ;AACA,OAAK,IAAI,IAAT,IAAiB,EAAjB,EAAqB;AACnB,QAAI,GAAG,cAAH,CAAkB,IAAlB,CAAJ,EACE,MAAM,IAAN,CAAW,IAAX;AACF,QAAI,QAAO,GAAG,IAAH,CAAP,MAAqB,QAArB,IAAiC,OAAO,GAAG,IAAH,EAAS,MAAhB,KAA4B,WAAjE,EAA8E;AAC5E,YAAM,IAAI,KAAJ,CAAU,2BAAV,CAAN;AACD,KAFD,MAEO,IAAI,OAAO,MAAP,KAAmB,WAAnB,IAAkC,WAAW,GAAG,IAAH,EAAS,MAA1D,EAAkE;AACvE,YAAM,IAAI,KAAJ,CAAU,8CAAV,CAAN;AACD;AACD,aAAS,GAAG,IAAH,EAAS,MAAlB;AACD;AACD,MAAI,UAAU,EAAd;AACA,MAAI,aAAJ;AACA,OAAK,IAAI,MAAM,CAAf,EAAkB,MAAM,MAAxB,EAAgC,KAAhC,EAAuC;AACrC,WAAO,EAAP;AACA,SAAK,IAAI,MAAM,CAAf,EAAkB,MAAM,MAAM,MAA9B,EAAsC,KAAtC,EAA6C;AAC3C,WAAK,MAAM,GAAN,CAAL,IAAmB,GAAG,MAAM,GAAN,CAAH,EAAe,GAAf,CAAnB;AACD;AACD,YAAQ,IAAR,CAAa,IAAb;AACD;AACD,SAAO,OAAP;AACD;;AAED;;;;;;;IAMa,mB,WAAA,mB;AACX,+BAAY,OAAZ,EAAqB;AAAA;;AACnB,SAAK,QAAL,GAAgB,OAAhB;AACA,SAAK,KAAL,GAAa,EAAb;AACD;;;;uBAEE,S,EAAW,Q,EAAU;AACtB,UAAI,MAAM,KAAK,QAAL,CAAc,EAAd,CAAiB,SAAjB,EAA4B,QAA5B,CAAV;AACA,WAAK,KAAL,CAAW,GAAX,IAAkB,SAAlB;AACA,aAAO,GAAP;AACD;;;wBAEG,S,EAAW,Q,EAAU;AACvB,UAAI,MAAM,KAAK,QAAL,CAAc,GAAd,CAAkB,SAAlB,EAA6B,QAA7B,CAAV;AACA,UAAI,GAAJ,EAAS;AACP,eAAO,KAAK,KAAL,CAAW,GAAX,CAAP;AACD;AACD,aAAO,GAAP;AACD;;;yCAEoB;AAAA;;AACnB,UAAI,eAAe,KAAK,KAAxB;AACA,WAAK,KAAL,GAAa,EAAb;AACA,aAAO,IAAP,CAAY,YAAZ,EAA0B,OAA1B,CAAkC,UAAC,GAAD,EAAS;AACzC,cAAK,QAAL,CAAc,GAAd,CAAkB,aAAa,GAAb,CAAlB,EAAqC,GAArC;AACD,OAFD;AAGD;;;;;;;;;;;;;;;;;;ACpHH;;;;;;;;IAEqB,G;AACnB,eAAY,KAAZ,EAAmB,IAAnB,EAAyB,YAAa,KAAtC,EAA6C;AAAA;;AAC3C,SAAK,MAAL,GAAc,KAAd;AACA,SAAK,KAAL,GAAa,IAAb;AACA,SAAK,MAAL,GAAc,KAAd;AACA,SAAK,OAAL,GAAe,sBAAf;AACD;;;;0BAEK;AACJ,aAAO,KAAK,MAAZ;AACD;;;wBAEG,K,EAAO,YAAa,K,EAAO;AAC7B,UAAI,KAAK,MAAL,KAAgB,KAApB,EAA2B;AACzB;AACA;AACD;AACD,UAAI,WAAW,KAAK,MAApB;AACA,WAAK,MAAL,GAAc,KAAd;AACA;AACA,UAAI,MAAM,EAAV;AACA,UAAI,SAAS,QAAO,KAAP,yCAAO,KAAP,OAAkB,QAA/B,EAAyC;AACvC,aAAK,IAAI,CAAT,IAAc,KAAd,EAAqB;AACnB,cAAI,MAAM,cAAN,CAAqB,CAArB,CAAJ,EACE,IAAI,CAAJ,IAAS,MAAM,CAAN,CAAT;AACH;AACF;AACD,UAAI,QAAJ,GAAe,QAAf;AACA,UAAI,KAAJ,GAAY,KAAZ;AACA,WAAK,OAAL,CAAa,OAAb,CAAqB,QAArB,EAA+B,GAA/B,EAAoC,IAApC;;AAEA;AACA;AACA,UAAI,OAAO,KAAP,IAAgB,OAAO,KAAP,CAAa,aAAjC,EAAgD;AAC9C,eAAO,KAAP,CAAa,aAAb,CACE,mBACG,KAAK,MAAL,CAAY,IAAZ,KAAqB,IAArB,GAA4B,KAAK,MAAL,CAAY,IAAZ,GAAmB,GAA/C,GAAqD,EADxD,IAEE,KAAK,KAHT,EAIE,OAAO,KAAP,KAAkB,WAAlB,GAAgC,IAAhC,GAAuC,KAJzC;AAMD;AACF;;;uBAEE,S,EAAW,Q,EAAU;AACtB,aAAO,KAAK,OAAL,CAAa,EAAb,CAAgB,SAAhB,EAA2B,QAA3B,CAAP;AACD;;;wBAEG,S,EAAW,Q,EAAU;AACvB,aAAO,KAAK,OAAL,CAAa,GAAb,CAAiB,SAAjB,EAA4B,QAA5B,CAAP;AACD;;;;;;kBAjDkB,G", + "file": "generated.js", + "sourceRoot": "", + "sourcesContent": [ + "(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n", + "import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n", + "import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n", + "import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n", + "let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n", + "import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n", + "import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n", + "export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n", + "import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n" + ] +} \ No newline at end of file diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.min.js b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.min.js new file mode 100644 index 0000000..b7ec0ac --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/js/crosstalk.min.js @@ -0,0 +1,2 @@ +!function o(u,a,l){function s(n,e){if(!a[n]){if(!u[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(f)return f(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var i=a[n]={exports:{}};u[n][0].call(i.exports,function(e){var t=u[n][1][e];return s(t||e)},i,i.exports,o,u,a,l)}return a[n].exports}for(var f="function"==typeof require&&require,e=0;e?@[\\\]^`{|}~])/g,"\\$1")+"']"),r=JSON.parse(n[0].innerText),i=e.factory(t,r);o(t).data("crosstalk-instance",i),o(t).addClass("crosstalk-input-bound")}if(t.Shiny){var e=new t.Shiny.InputBinding,u=t.jQuery;u.extend(e,{find:function(e){return u(e).find(".crosstalk-input")},initialize:function(e){var t,n;u(e).hasClass("crosstalk-input-bound")||(n=o(t=e),Object.keys(r).forEach(function(e){n.hasClass(e)&&!n.hasClass("crosstalk-input-bound")&&i(r[e],t)}))},getId:function(e){return e.id},getValue:function(e){},setValue:function(e,t){},receiveMessage:function(e,t){},subscribe:function(e,t){u(e).data("crosstalk-instance").resume()},unsubscribe:function(e){u(e).data("crosstalk-instance").suspend()}}),t.Shiny.inputBindings.register(e,"crosstalk.inputBinding")}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(r,e,t){(function(e){"use strict";var t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(r("./input")),n=r("./filter");var a=e.jQuery;t.register({className:"crosstalk-input-checkboxgroup",factory:function(e,r){var i=new n.FilterHandle(r.group),o=void 0,u=a(e);return u.on("change","input[type='checkbox']",function(){var e=u.find("input[type='checkbox']:checked");if(0===e.length)o=null,i.clear();else{var t={};e.each(function(){r.map[this.value].forEach(function(e){t[e]=!0})});var n=Object.keys(t);n.sort(),o=n,i.set(n)}}),{suspend:function(){i.clear()},resume:function(){o&&i.set(o)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6}],8:[function(r,e,t){(function(e){"use strict";var t=n(r("./input")),l=n(r("./util")),s=r("./filter");function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var f=e.jQuery;t.register({className:"crosstalk-input-select",factory:function(e,n){var t=l.dataframeToD3(n.items),r={options:[{value:"",label:"(All)"}].concat(t),valueField:"value",labelField:"label",searchField:"label"},i=f(e).find("select")[0],o=f(i).selectize(r)[0].selectize,u=new s.FilterHandle(n.group),a=void 0;return o.on("change",function(){if(0===o.items.length)a=null,u.clear();else{var t={};o.items.forEach(function(e){n.map[e].forEach(function(e){t[e]=!0})});var e=Object.keys(t);e.sort(),a=e,u.set(e)}}),{suspend:function(){u.clear()},resume:function(){a&&u.set(a)}}}})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{"./filter":2,"./input":6,"./util":11}],9:[function(n,e,t){(function(e){"use strict";var d=function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return function(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")},t=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}}(n("./input")),a=n("./filter");var v=e.jQuery,p=e.strftime;function y(e,t){for(var n=e.toString();n.length {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Combine the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Close the handle. This clears this handle's contribution to the filter set,\n * and unsubscribes all event listeners.\n */\n close() {\n this._emitter.removeAllListeners();\n this.clear();\n this.setGroup(null);\n }\n\n /**\n * Clear this handle's contribution to the filter set.\n *\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n clear(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.clear(this._id);\n this._onChange(extraInfo);\n }\n\n /**\n * Set this handle's contribution to the filter set. This array should consist\n * of the keys of the rows that _should_ be displayed; any keys that are not\n * present in the array will be considered _filtered out_. Note that multiple\n * `FilterHandle` instances in the group may each contribute an array of keys,\n * and only those keys that appear in _all_ of the arrays make it through the\n * filter.\n *\n * @param {string[]} keys - Empty array, or array of keys. To clear the\n * filter, don't pass an empty array; instead, use the\n * {@link FilterHandle#clear} method.\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `FilterHandle` constructor).\n * \n * @fires FilterHandle#change\n */\n set(keys, extraInfo) {\n if (!this._filterSet)\n return;\n this._filterSet.update(this._id, keys);\n this._onChange(extraInfo);\n }\n\n /**\n * @return {string[]|null} - Either: 1) an array of keys that made it through\n * all of the `FilterHandle` instances, or, 2) `null`, which means no filter\n * is being applied (all data should be displayed).\n */\n get filteredKeys() {\n return this._filterSet ? this._filterSet.value : null;\n }\n\n /**\n * Subscribe to events on this `FilterHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {FilterHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link FilterHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancel event subscriptions created by {@link FilterHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|FilterHandle~listener} listener - Either the callback\n * function previously passed into {@link FilterHandle#on}, or the\n * string that was returned from {@link FilterHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n _onChange(extraInfo) {\n if (!this._filterSet)\n return;\n this._filterVar.set(this._filterSet.value, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * @callback FilterHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the filter set, or `null` if no filter set is active),\n * `oldValue` (the previous value of the filter set), and `sender` (the\n * `FilterHandle` instance that made the change).\n */\n\n}\n\n/**\n * @event FilterHandle#change\n * @type {object}\n * @property {object} value - The new value of the filter set, or `null`\n * if no filter set is active.\n * @property {object} oldValue - The previous value of the filter set.\n * @property {FilterHandle} sender - The `FilterHandle` instance that\n * changed the value.\n */\n","import { diffSortedLists } from \"./util\";\n\nfunction naturalComparator(a, b) {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else if (a > b) {\n return 1;\n }\n}\n\n/**\n * @private\n */\nexport default class FilterSet {\n constructor() {\n this.reset();\n }\n\n reset() {\n // Key: handle ID, Value: array of selected keys, or null\n this._handles = {};\n // Key: key string, Value: count of handles that include it\n this._keys = {};\n this._value = null;\n this._activeHandles = 0;\n }\n\n get value() {\n return this._value;\n }\n\n update(handleId, keys) {\n if (keys !== null) {\n keys = keys.slice(0); // clone before sorting\n keys.sort(naturalComparator);\n }\n\n let {added, removed} = diffSortedLists(this._handles[handleId], keys);\n this._handles[handleId] = keys;\n\n for (let i = 0; i < added.length; i++) {\n this._keys[added[i]] = (this._keys[added[i]] || 0) + 1;\n }\n for (let i = 0; i < removed.length; i++) {\n this._keys[removed[i]]--;\n }\n\n this._updateValue(keys);\n }\n\n /**\n * @param {string[]} keys Sorted array of strings that indicate\n * a superset of possible keys.\n * @private\n */\n _updateValue(keys = this._allKeys) {\n let handleCount = Object.keys(this._handles).length;\n if (handleCount === 0) {\n this._value = null;\n } else {\n this._value = [];\n for (let i = 0; i < keys.length; i++) {\n let count = this._keys[keys[i]];\n if (count === handleCount) {\n this._value.push(keys[i]);\n }\n }\n }\n }\n\n clear(handleId) {\n if (typeof(this._handles[handleId]) === \"undefined\") {\n return;\n }\n\n let keys = this._handles[handleId];\n if (!keys) {\n keys = [];\n }\n\n for (let i = 0; i < keys.length; i++) {\n this._keys[keys[i]]--;\n }\n delete this._handles[handleId];\n\n this._updateValue();\n }\n\n get _allKeys() {\n let allKeys = Object.keys(this._keys);\n allKeys.sort(naturalComparator);\n return allKeys;\n }\n}\n","import Var from \"./var\";\n\n// Use a global so that multiple copies of crosstalk.js can be loaded and still\n// have groups behave as singletons across all copies.\nglobal.__crosstalk_groups = global.__crosstalk_groups || {};\nlet groups = global.__crosstalk_groups;\n\nexport default function group(groupName) {\n if (groupName && typeof(groupName) === \"string\") {\n if (!groups.hasOwnProperty(groupName)) {\n groups[groupName] = new Group(groupName);\n }\n return groups[groupName];\n } else if (typeof(groupName) === \"object\" && groupName._vars && groupName.var) {\n // Appears to already be a group object\n return groupName;\n } else if (Array.isArray(groupName) &&\n groupName.length == 1 &&\n typeof(groupName[0]) === \"string\") {\n return group(groupName[0]);\n } else {\n throw new Error(\"Invalid groupName argument\");\n }\n}\n\nclass Group {\n constructor(name) {\n this.name = name;\n this._vars = {};\n }\n\n var(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n if (!this._vars.hasOwnProperty(name))\n this._vars[name] = new Var(this, name);\n return this._vars[name];\n }\n\n has(name) {\n if (!name || typeof(name) !== \"string\") {\n throw new Error(\"Invalid var name\");\n }\n\n return this._vars.hasOwnProperty(name);\n }\n}\n","import group from \"./group\";\nimport { SelectionHandle } from \"./selection\";\nimport { FilterHandle } from \"./filter\";\nimport { bind } from \"./input\";\nimport \"./input_selectize\";\nimport \"./input_checkboxgroup\";\nimport \"./input_slider\";\n\nconst defaultGroup = group(\"default\");\n\nfunction var_(name) {\n return defaultGroup.var(name);\n}\n\nfunction has(name) {\n return defaultGroup.has(name);\n}\n\nif (global.Shiny) {\n global.Shiny.addCustomMessageHandler(\"update-client-value\", function(message) {\n if (typeof(message.group) === \"string\") {\n group(message.group).var(message.name).set(message.value);\n } else {\n var_(message.name).set(message.value);\n }\n });\n}\n\nconst crosstalk = {\n group: group,\n var: var_,\n has: has,\n SelectionHandle: SelectionHandle,\n FilterHandle: FilterHandle,\n bind: bind\n};\n\n/**\n * @namespace crosstalk\n */\nexport default crosstalk;\nglobal.crosstalk = crosstalk;\n","let $ = global.jQuery;\n\nlet bindings = {};\n\nexport function register(reg) {\n bindings[reg.className] = reg;\n if (global.document && global.document.readyState !== \"complete\") {\n $(() => {\n bind();\n });\n } else if (global.document) {\n setTimeout(bind, 100);\n }\n}\n\nexport function bind() {\n Object.keys(bindings).forEach(function(className) {\n let binding = bindings[className];\n $(\".\" + binding.className).not(\".crosstalk-input-bound\").each(function(i, el) {\n bindInstance(binding, el);\n });\n });\n}\n\n// Escape jQuery identifier\nfunction $escape(val) {\n return val.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\nfunction bindEl(el) {\n let $el = $(el);\n Object.keys(bindings).forEach(function(className) {\n if ($el.hasClass(className) && !$el.hasClass(\"crosstalk-input-bound\")) {\n let binding = bindings[className];\n bindInstance(binding, el);\n }\n });\n}\n\nfunction bindInstance(binding, el) {\n let jsonEl = $(el).find(\"script[type='application/json'][data-for='\" + $escape(el.id) + \"']\");\n let data = JSON.parse(jsonEl[0].innerText);\n\n let instance = binding.factory(el, data);\n $(el).data(\"crosstalk-instance\", instance);\n $(el).addClass(\"crosstalk-input-bound\");\n}\n\nif (global.Shiny) {\n let inputBinding = new global.Shiny.InputBinding();\n let $ = global.jQuery;\n $.extend(inputBinding, {\n find: function(scope) {\n return $(scope).find(\".crosstalk-input\");\n },\n initialize: function(el) {\n if (!$(el).hasClass(\"crosstalk-input-bound\")) {\n bindEl(el);\n }\n },\n getId: function(el) {\n return el.id;\n },\n getValue: function(el) {\n\n },\n setValue: function(el, value) {\n\n },\n receiveMessage: function(el, data) {\n\n },\n subscribe: function(el, callback) {\n $(el).data(\"crosstalk-instance\").resume();\n },\n unsubscribe: function(el) {\n $(el).data(\"crosstalk-instance\").suspend();\n }\n });\n global.Shiny.inputBindings.register(inputBinding, \"crosstalk.inputBinding\");\n}\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-checkboxgroup\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n let $el = $(el);\n $el.on(\"change\", \"input[type='checkbox']\", function() {\n let checked = $el.find(\"input[type='checkbox']:checked\");\n if (checked.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n checked.each(function() {\n data.map[this.value].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport * as util from \"./util\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\n\ninput.register({\n className: \"crosstalk-input-select\",\n\n factory: function(el, data) {\n /*\n * items: {value: [...], label: [...]}\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n\n let first = [{value: \"\", label: \"(All)\"}];\n let items = util.dataframeToD3(data.items);\n let opts = {\n options: first.concat(items),\n valueField: \"value\",\n labelField: \"label\",\n searchField: \"label\"\n };\n\n let select = $(el).find(\"select\")[0];\n\n let selectize = $(select).selectize(opts)[0].selectize;\n\n let ctHandle = new FilterHandle(data.group);\n\n let lastKnownKeys;\n selectize.on(\"change\", function() {\n if (selectize.items.length === 0) {\n lastKnownKeys = null;\n ctHandle.clear();\n } else {\n let keys = {};\n selectize.items.forEach(function(group) {\n data.map[group].forEach(function(key) {\n keys[key] = true;\n });\n });\n let keyArray = Object.keys(keys);\n keyArray.sort();\n lastKnownKeys = keyArray;\n ctHandle.set(keyArray);\n }\n });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n","import * as input from \"./input\";\nimport { FilterHandle } from \"./filter\";\n\nlet $ = global.jQuery;\nlet strftime = global.strftime;\n\ninput.register({\n className: \"crosstalk-input-slider\",\n\n factory: function(el, data) {\n /*\n * map: {\"groupA\": [\"keyA\", \"keyB\", ...], ...}\n * group: \"ct-groupname\"\n */\n let ctHandle = new FilterHandle(data.group);\n\n let opts = {};\n let $el = $(el).find(\"input\");\n let dataType = $el.data(\"data-type\");\n let timeFormat = $el.data(\"time-format\");\n let round = $el.data(\"round\");\n let timeFormatter;\n\n // Set up formatting functions\n if (dataType === \"date\") {\n timeFormatter = strftime.utc();\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n\n } else if (dataType === \"datetime\") {\n let timezone = $el.data(\"timezone\");\n if (timezone)\n timeFormatter = strftime.timezone(timezone);\n else\n timeFormatter = strftime;\n\n opts.prettify = function(num) {\n return timeFormatter(timeFormat, new Date(num));\n };\n } else if (dataType === \"number\") {\n if (typeof round !== \"undefined\")\n opts.prettify = function(num) {\n let factor = Math.pow(10, round);\n return Math.round(num * factor) / factor;\n };\n }\n\n $el.ionRangeSlider(opts);\n\n function getValue() {\n let result = $el.data(\"ionRangeSlider\").result;\n\n // Function for converting numeric value from slider to appropriate type.\n let convert;\n let dataType = $el.data(\"data-type\");\n if (dataType === \"date\") {\n convert = function(val) {\n return formatDateUTC(new Date(+val));\n };\n } else if (dataType === \"datetime\") {\n convert = function(val) {\n // Convert ms to s\n return +val / 1000;\n };\n } else {\n convert = function(val) { return +val; };\n }\n\n if ($el.data(\"ionRangeSlider\").options.type === \"double\") {\n return [convert(result.from), convert(result.to)];\n } else {\n return convert(result.from);\n }\n }\n\n let lastKnownKeys = null;\n\n $el.on(\"change.crosstalkSliderInput\", function(event) {\n if (!$el.data(\"updating\") && !$el.data(\"animating\")) {\n let [from, to] = getValue();\n let keys = [];\n for (let i = 0; i < data.values.length; i++) {\n let val = data.values[i];\n if (val >= from && val <= to) {\n keys.push(data.keys[i]);\n }\n }\n keys.sort();\n ctHandle.set(keys);\n lastKnownKeys = keys;\n }\n });\n\n\n // let $el = $(el);\n // $el.on(\"change\", \"input[type=\"checkbox\"]\", function() {\n // let checked = $el.find(\"input[type=\"checkbox\"]:checked\");\n // if (checked.length === 0) {\n // ctHandle.clear();\n // } else {\n // let keys = {};\n // checked.each(function() {\n // data.map[this.value].forEach(function(key) {\n // keys[key] = true;\n // });\n // });\n // let keyArray = Object.keys(keys);\n // keyArray.sort();\n // ctHandle.set(keyArray);\n // }\n // });\n\n return {\n suspend: function() {\n ctHandle.clear();\n },\n resume: function() {\n if (lastKnownKeys)\n ctHandle.set(lastKnownKeys);\n }\n };\n }\n});\n\n\n// Convert a number to a string with leading zeros\nfunction padZeros(n, digits) {\n let str = n.toString();\n while (str.length < digits)\n str = \"0\" + str;\n return str;\n}\n\n// Given a Date object, return a string in yyyy-mm-dd format, using the\n// UTC date. This may be a day off from the date in the local time zone.\nfunction formatDateUTC(date) {\n if (date instanceof Date) {\n return date.getUTCFullYear() + \"-\" +\n padZeros(date.getUTCMonth()+1, 2) + \"-\" +\n padZeros(date.getUTCDate(), 2);\n\n } else {\n return null;\n }\n}\n","import Events from \"./events\";\nimport grp from \"./group\";\nimport * as util from \"./util\";\n\n/**\n * Use this class to read and write (and listen for changes to) the selection\n * for a Crosstalk group. This is intended to be used for linked brushing.\n *\n * If two (or more) `SelectionHandle` instances in the same webpage share the\n * same group name, they will share the same state. Setting the selection using\n * one `SelectionHandle` instance will result in the `value` property instantly\n * changing across the others, and `\"change\"` event listeners on all instances\n * (including the one that initiated the sending) will fire.\n *\n * @param {string} [group] - The name of the Crosstalk group, or if none,\n * null or undefined (or any other falsy value). This can be changed later\n * via the [SelectionHandle#setGroup](#setGroup) method.\n * @param {Object} [extraInfo] - An object whose properties will be copied to\n * the event object whenever an event is emitted.\n */\nexport class SelectionHandle {\n\n constructor(group = null, extraInfo = null) {\n this._eventRelay = new Events();\n this._emitter = new util.SubscriptionTracker(this._eventRelay);\n\n // Name of the group we're currently tracking, if any. Can change over time.\n this._group = null;\n // The Var we're currently tracking, if any. Can change over time.\n this._var = null;\n // The event handler subscription we currently have on var.on(\"change\").\n this._varOnChangeSub = null;\n\n this._extraInfo = util.extend({ sender: this }, extraInfo);\n\n this.setGroup(group);\n }\n\n /**\n * Changes the Crosstalk group membership of this SelectionHandle. The group\n * being switched away from (if any) will not have its selection value\n * modified as a result of calling `setGroup`, even if this handle was the\n * most recent handle to set the selection of the group.\n *\n * The group being switched to (if any) will also not have its selection value\n * modified as a result of calling `setGroup`. If you want to set the\n * selection value of the new group, call `set` explicitly.\n *\n * @param {string} group - The name of the Crosstalk group, or null (or\n * undefined) to clear the group.\n */\n setGroup(group) {\n // If group is unchanged, do nothing\n if (this._group === group)\n return;\n // Treat null, undefined, and other falsy values the same\n if (!this._group && !group)\n return;\n\n if (this._var) {\n this._var.off(\"change\", this._varOnChangeSub);\n this._var = null;\n this._varOnChangeSub = null;\n }\n\n this._group = group;\n\n if (group) {\n this._var = grp(group).var(\"selection\");\n let sub = this._var.on(\"change\", (e) => {\n this._eventRelay.trigger(\"change\", e, this);\n });\n this._varOnChangeSub = sub;\n }\n }\n\n /**\n * Retrieves the current selection for the group represented by this\n * `SelectionHandle`.\n *\n * - If no selection is active, then this value will be falsy.\n * - If a selection is active, but no data points are selected, then this\n * value will be an empty array.\n * - If a selection is active, and data points are selected, then the keys\n * of the selected data points will be present in the array.\n */\n get value() {\n return this._var ? this._var.get() : null;\n }\n\n /**\n * Combines the given `extraInfo` (if any) with the handle's default\n * `_extraInfo` (if any).\n * @private\n */\n _mergeExtraInfo(extraInfo) {\n // Important incidental effect: shallow clone is returned\n return util.extend({},\n this._extraInfo ? this._extraInfo : null,\n extraInfo ? extraInfo : null);\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {string[]} selectedKeys - Falsy, empty array, or array of keys (see\n * {@link SelectionHandle#value}).\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any options that were\n * passed into the `SelectionHandle` constructor).\n */\n set(selectedKeys, extraInfo) {\n if (this._var)\n this._var.set(selectedKeys, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Overwrites the current selection for the group, and raises the `\"change\"`\n * event among all of the group's '`SelectionHandle` instances (including\n * this one).\n *\n * @fires SelectionHandle#change\n * @param {Object} [extraInfo] - Extra properties to be included on the event\n * object that's passed to listeners (in addition to any that were passed\n * into the `SelectionHandle` constructor).\n */\n clear(extraInfo) {\n if (this._var)\n this.set(void 0, this._mergeExtraInfo(extraInfo));\n }\n\n /**\n * Subscribes to events on this `SelectionHandle`.\n *\n * @param {string} eventType - Indicates the type of events to listen to.\n * Currently, only `\"change\"` is supported.\n * @param {SelectionHandle~listener} listener - The callback function that\n * will be invoked when the event occurs.\n * @return {string} - A token to pass to {@link SelectionHandle#off} to cancel\n * this subscription.\n */\n on(eventType, listener) {\n return this._emitter.on(eventType, listener);\n }\n\n /**\n * Cancels event subscriptions created by {@link SelectionHandle#on}.\n *\n * @param {string} eventType - The type of event to unsubscribe.\n * @param {string|SelectionHandle~listener} listener - Either the callback\n * function previously passed into {@link SelectionHandle#on}, or the\n * string that was returned from {@link SelectionHandle#on}.\n */\n off(eventType, listener) {\n return this._emitter.off(eventType, listener);\n }\n\n /**\n * Shuts down the `SelectionHandle` object.\n *\n * Removes all event listeners that were added through this handle.\n */\n close() {\n this._emitter.removeAllListeners();\n this.setGroup(null);\n }\n}\n\n/**\n * @callback SelectionHandle~listener\n * @param {Object} event - An object containing details of the event. For\n * `\"change\"` events, this includes the properties `value` (the new\n * value of the selection, or `undefined` if no selection is active),\n * `oldValue` (the previous value of the selection), and `sender` (the\n * `SelectionHandle` instance that made the change).\n */\n\n/**\n * @event SelectionHandle#change\n * @type {object}\n * @property {object} value - The new value of the selection, or `undefined`\n * if no selection is active.\n * @property {object} oldValue - The previous value of the selection.\n * @property {SelectionHandle} sender - The `SelectionHandle` instance that\n * changed the value.\n */\n","export function extend(target, ...sources) {\n for (let i = 0; i < sources.length; i++) {\n let src = sources[i];\n if (typeof(src) === \"undefined\" || src === null)\n continue;\n\n for (let key in src) {\n if (src.hasOwnProperty(key)) {\n target[key] = src[key];\n }\n }\n }\n return target;\n}\n\nexport function checkSorted(list) {\n for (let i = 1; i < list.length; i++) {\n if (list[i] <= list[i-1]) {\n throw new Error(\"List is not sorted or contains duplicate\");\n }\n }\n}\n\nexport function diffSortedLists(a, b) {\n let i_a = 0;\n let i_b = 0;\n\n if (!a) a = [];\n if (!b) b = [];\n\n let a_only = [];\n let b_only = [];\n\n checkSorted(a);\n checkSorted(b);\n\n while (i_a < a.length && i_b < b.length) {\n if (a[i_a] === b[i_b]) {\n i_a++;\n i_b++;\n } else if (a[i_a] < b[i_b]) {\n a_only.push(a[i_a++]);\n } else {\n b_only.push(b[i_b++]);\n }\n }\n\n if (i_a < a.length)\n a_only = a_only.concat(a.slice(i_a));\n if (i_b < b.length)\n b_only = b_only.concat(b.slice(i_b));\n return {\n removed: a_only,\n added: b_only\n };\n}\n\n// Convert from wide: { colA: [1,2,3], colB: [4,5,6], ... }\n// to long: [ {colA: 1, colB: 4}, {colA: 2, colB: 5}, ... ]\nexport function dataframeToD3(df) {\n let names = [];\n let length;\n for (let name in df) {\n if (df.hasOwnProperty(name))\n names.push(name);\n if (typeof(df[name]) !== \"object\" || typeof(df[name].length) === \"undefined\") {\n throw new Error(\"All fields must be arrays\");\n } else if (typeof(length) !== \"undefined\" && length !== df[name].length) {\n throw new Error(\"All fields must be arrays of the same length\");\n }\n length = df[name].length;\n }\n let results = [];\n let item;\n for (let row = 0; row < length; row++) {\n item = {};\n for (let col = 0; col < names.length; col++) {\n item[names[col]] = df[names[col]][row];\n }\n results.push(item);\n }\n return results;\n}\n\n/**\n * Keeps track of all event listener additions/removals and lets all active\n * listeners be removed with a single operation.\n *\n * @private\n */\nexport class SubscriptionTracker {\n constructor(emitter) {\n this._emitter = emitter;\n this._subs = {};\n }\n\n on(eventType, listener) {\n let sub = this._emitter.on(eventType, listener);\n this._subs[sub] = eventType;\n return sub;\n }\n\n off(eventType, listener) {\n let sub = this._emitter.off(eventType, listener);\n if (sub) {\n delete this._subs[sub];\n }\n return sub;\n }\n\n removeAllListeners() {\n let current_subs = this._subs;\n this._subs = {};\n Object.keys(current_subs).forEach((sub) => {\n this._emitter.off(current_subs[sub], sub);\n });\n }\n}\n","import Events from \"./events\";\n\nexport default class Var {\n constructor(group, name, /*optional*/ value) {\n this._group = group;\n this._name = name;\n this._value = value;\n this._events = new Events();\n }\n\n get() {\n return this._value;\n }\n\n set(value, /*optional*/ event) {\n if (this._value === value) {\n // Do nothing; the value hasn't changed\n return;\n }\n let oldValue = this._value;\n this._value = value;\n // Alert JavaScript listeners that the value has changed\n let evt = {};\n if (event && typeof(event) === \"object\") {\n for (let k in event) {\n if (event.hasOwnProperty(k))\n evt[k] = event[k];\n }\n }\n evt.oldValue = oldValue;\n evt.value = value;\n this._events.trigger(\"change\", evt, this);\n\n // TODO: Make this extensible, to let arbitrary back-ends know that\n // something has changed\n if (global.Shiny && global.Shiny.onInputChange) {\n global.Shiny.onInputChange(\n \".clientValue-\" +\n (this._group.name !== null ? this._group.name + \"-\" : \"\") +\n this._name,\n typeof(value) === \"undefined\" ? null : value\n );\n }\n }\n\n on(eventType, listener) {\n return this._events.on(eventType, listener);\n }\n\n off(eventType, listener) {\n return this._events.off(eventType, listener);\n }\n}\n"]} \ No newline at end of file diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/scss/crosstalk.scss b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/scss/crosstalk.scss new file mode 100644 index 0000000..3566561 --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/crosstalk/scss/crosstalk.scss @@ -0,0 +1,75 @@ +/* Adjust margins outwards, so column contents line up with the edges of the + parent of container-fluid. */ +.container-fluid.crosstalk-bscols { + margin-left: -30px; + margin-right: -30px; + white-space: normal; +} + +/* But don't adjust the margins outwards if we're directly under the body, + i.e. we were the top-level of something at the console. */ +body > .container-fluid.crosstalk-bscols { + margin-left: auto; + margin-right: auto; +} + +.crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: inline-block; + padding-right: 12px; + vertical-align: top; +} + +@media only screen and (max-width:480px) { + .crosstalk-input-checkboxgroup .crosstalk-options-group .crosstalk-options-column { + display: block; + padding-right: inherit; + } +} + +/* Relevant BS3 styles to make filter_checkbox() look reasonable without Bootstrap */ +.crosstalk-input { + margin-bottom: 15px; /* a la .form-group */ + .control-label { + margin-bottom: 0; + vertical-align: middle; + } + input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px; + line-height: normal; + } + .checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; + } + .checkbox > label{ + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + cursor: pointer; + } + .checkbox input[type="checkbox"], + .checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 2px; + margin-left: -20px; + } + .checkbox + .checkbox { + margin-top: -5px; + } + .checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: 400; + vertical-align: middle; + cursor: pointer; + } + .checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; + } +} diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-binding/datatables.js b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-binding/datatables.js new file mode 100644 index 0000000..765b53c --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-binding/datatables.js @@ -0,0 +1,1539 @@ +(function() { + +// some helper functions: using a global object DTWidget so that it can be used +// in JS() code, e.g. datatable(options = list(foo = JS('code'))); unlike R's +// dynamic scoping, when 'code' is eval'ed, JavaScript does not know objects +// from the "parent frame", e.g. JS('DTWidget') will not work unless it was made +// a global object +var DTWidget = {}; + +// 123456666.7890 -> 123,456,666.7890 +var markInterval = function(d, digits, interval, mark, decMark, precision) { + x = precision ? d.toPrecision(digits) : d.toFixed(digits); + if (!/^-?[\d.]+$/.test(x)) return x; + var xv = x.split('.'); + if (xv.length > 2) return x; // should have at most one decimal point + xv[0] = xv[0].replace(new RegExp('\\B(?=(\\d{' + interval + '})+(?!\\d))', 'g'), mark); + return xv.join(decMark); +}; + +DTWidget.formatCurrency = function(data, currency, digits, interval, mark, decMark, before, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + var res = markInterval(d, digits, interval, mark, decMark); + res = before ? (/^-/.test(res) ? '-' + currency + res.replace(/^-/, '') : currency + res) : + res + currency; + return res; +}; + +DTWidget.formatString = function(data, prefix, suffix) { + var d = data; + if (d === null) return ''; + return prefix + d + suffix; +}; + +DTWidget.formatPercentage = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d * 100, digits, interval, mark, decMark) + '%'; +}; + +DTWidget.formatRound = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark); +}; + +DTWidget.formatSignif = function(data, digits, interval, mark, decMark, zeroPrint) { + var d = parseFloat(data); + if (isNaN(d)) return ''; + if (zeroPrint !== null && d === 0.0) return zeroPrint; + return markInterval(d, digits, interval, mark, decMark, true); +}; + +DTWidget.formatDate = function(data, method, params) { + var d = data; + if (d === null) return ''; + // (new Date('2015-10-28')).toDateString() may return 2015-10-27 because the + // actual time created could be like 'Tue Oct 27 2015 19:00:00 GMT-0500 (CDT)', + // i.e. the date-only string is treated as UTC time instead of local time + if ((method === 'toDateString' || method === 'toLocaleDateString') && /^\d{4,}\D\d{2}\D\d{2}$/.test(d)) { + d = d.split(/\D/); + d = new Date(d[0], d[1] - 1, d[2]); + } else { + d = new Date(d); + } + return d[method].apply(d, params); +}; + +window.DTWidget = DTWidget; + +// A helper function to update the properties of existing filters +var setFilterProps = function(td, props) { + // Update enabled/disabled state + var $input = $(td).find('input').first(); + var searchable = $input.data('searchable'); + $input.prop('disabled', !searchable || props.disabled); + + // Based on the filter type, set its new values + var type = td.getAttribute('data-type'); + if (['factor', 'logical'].includes(type)) { + // Reformat the new dropdown options for use with selectize + var new_vals = props.params.options.map(function(item) { + return { text: item, value: item }; + }); + + // Find the selectize object + var dropdown = $(td).find('.selectized').eq(0)[0].selectize; + + // Note the current values + var old_vals = dropdown.getValue(); + + // Remove the existing values + dropdown.clearOptions(); + + // Add the new options + dropdown.addOption(new_vals); + + // Preserve the existing values + dropdown.setValue(old_vals); + + } else if (['number', 'integer', 'date', 'time'].includes(type)) { + // Apply internal scaling to new limits. Updating scale not yet implemented. + var slider = $(td).find('.noUi-target').eq(0); + var scale = Math.pow(10, Math.max(0, +slider.data('scale') || 0)); + var new_vals = [props.params.min * scale, props.params.max * scale]; + + // Note what the new limits will be just for this filter + var new_lims = new_vals.slice(); + + // Determine the current values and limits + var old_vals = slider.val().map(Number); + var old_lims = slider.noUiSlider('options').range; + old_lims = [old_lims.min, old_lims.max]; + + // Preserve the current values if filters have been applied; otherwise, apply no filtering + if (old_vals[0] != old_lims[0]) { + new_vals[0] = Math.max(old_vals[0], new_vals[0]); + } + + if (old_vals[1] != old_lims[1]) { + new_vals[1] = Math.min(old_vals[1], new_vals[1]); + } + + // Update the endpoints of the slider + slider.noUiSlider({ + start: new_vals, + range: {'min': new_lims[0], 'max': new_lims[1]} + }, true); + } +}; + +var transposeArray2D = function(a) { + return a.length === 0 ? a : HTMLWidgets.transposeArray2D(a); +}; + +var crosstalkPluginsInstalled = false; + +function maybeInstallCrosstalkPlugins() { + if (crosstalkPluginsInstalled) + return; + crosstalkPluginsInstalled = true; + + $.fn.dataTable.ext.afnFiltering.push( + function(oSettings, aData, iDataIndex) { + var ctfilter = oSettings.nTable.ctfilter; + if (ctfilter && !ctfilter[iDataIndex]) + return false; + + var ctselect = oSettings.nTable.ctselect; + if (ctselect && !ctselect[iDataIndex]) + return false; + + return true; + } + ); +} + +HTMLWidgets.widget({ + name: "datatables", + type: "output", + renderOnNullValue: true, + initialize: function(el, width, height) { + // in order that the type=number inputs return a number + $.valHooks.number = { + get: function(el) { + var value = parseFloat(el.value); + return isNaN(value) ? "" : value; + } + }; + $(el).html(' '); + return { + data: null, + ctfilterHandle: new crosstalk.FilterHandle(), + ctfilterSubscription: null, + ctselectHandle: new crosstalk.SelectionHandle(), + ctselectSubscription: null + }; + }, + renderValue: function(el, data, instance) { + if (el.offsetWidth === 0 || el.offsetHeight === 0) { + instance.data = data; + return; + } + instance.data = null; + var $el = $(el); + $el.empty(); + + if (data === null) { + $el.append(' '); + // clear previous Shiny inputs (if any) + for (var i in instance.clearInputs) instance.clearInputs[i](); + instance.clearInputs = {}; + return; + } + + var crosstalkOptions = data.crosstalkOptions; + if (!crosstalkOptions) crosstalkOptions = { + 'key': null, 'group': null + }; + if (crosstalkOptions.group) { + maybeInstallCrosstalkPlugins(); + instance.ctfilterHandle.setGroup(crosstalkOptions.group); + instance.ctselectHandle.setGroup(crosstalkOptions.group); + } + + // if we are in the viewer then we always want to fillContainer and + // and autoHideNavigation (unless the user has explicitly set these) + if (window.HTMLWidgets.viewerMode) { + if (!data.hasOwnProperty("fillContainer")) + data.fillContainer = true; + if (!data.hasOwnProperty("autoHideNavigation")) + data.autoHideNavigation = true; + } + + // propagate fillContainer to instance (so we have it in resize) + instance.fillContainer = data.fillContainer; + + var cells = data.data; + + if (cells instanceof Array) cells = transposeArray2D(cells); + + $el.append(data.container); + var $table = $el.find('table'); + if (data.class) $table.addClass(data.class); + if (data.caption) $table.prepend(data.caption); + + if (!data.selection) data.selection = { + mode: 'none', selected: null, target: 'row', selectable: null + }; + if (HTMLWidgets.shinyMode && data.selection.mode !== 'none' && + data.selection.target === 'row+column') { + if ($table.children('tfoot').length === 0) { + $table.append($('')); + $table.find('thead tr').clone().appendTo($table.find('tfoot')); + } + } + + // column filters + var filterRow; + switch (data.filter) { + case 'top': + $table.children('thead').append(data.filterHTML); + filterRow = $table.find('thead tr:last td'); + break; + case 'bottom': + if ($table.children('tfoot').length === 0) { + $table.append($('')); + } + $table.children('tfoot').prepend(data.filterHTML); + filterRow = $table.find('tfoot tr:first td'); + break; + } + + var options = { searchDelay: 1000 }; + if (cells !== null) $.extend(options, { + data: cells + }); + + // options for fillContainer + var bootstrapActive = typeof($.fn.popover) != 'undefined'; + if (instance.fillContainer) { + + // force scrollX/scrollY and turn off autoWidth + options.scrollX = true; + options.scrollY = "100px"; // can be any value, we'll adjust below + + // if we aren't paginating then move around the info/filter controls + // to save space at the bottom and rephrase the info callback + if (data.options.paging === false) { + + // we know how to do this cleanly for bootstrap, not so much + // for other themes/layouts + if (bootstrapActive) { + options.dom = "<'row'<'col-sm-4'i><'col-sm-8'f>>" + + "<'row'<'col-sm-12'tr>>"; + } + + options.fnInfoCallback = function(oSettings, iStart, iEnd, + iMax, iTotal, sPre) { + return Number(iTotal).toLocaleString() + " records"; + }; + } + } + + // auto hide navigation if requested + // Note, this only works on client-side processing mode as on server-side, + // cells (data.data) is null; In addition, we require the pageLength option + // being provided explicitly to enable this. Despite we may be able to deduce + // the default value of pageLength, it may complicate things so we'd rather + // put this responsiblity to users and warn them on the R side. + if (data.autoHideNavigation === true && data.options.paging !== false) { + // strip all nav if length >= cells + if ((cells instanceof Array) && data.options.pageLength >= cells.length) + options.dom = bootstrapActive ? "<'row'<'col-sm-12'tr>>" : "t"; + // alternatively lean things out for flexdashboard mobile portrait + else if (bootstrapActive && window.FlexDashboard && window.FlexDashboard.isMobilePhone()) + options.dom = "<'row'<'col-sm-12'f>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-12'p>>"; + } + + $.extend(true, options, data.options || {}); + + var searchCols = options.searchCols; + if (searchCols) { + searchCols = searchCols.map(function(x) { + return x === null ? '' : x.search; + }); + // FIXME: this means I don't respect the escapeRegex setting + delete options.searchCols; + } + + // server-side processing? + var server = options.serverSide === true; + + // use the dataSrc function to pre-process JSON data returned from R + var DT_rows_all = [], DT_rows_current = []; + if (server && HTMLWidgets.shinyMode && typeof options.ajax === 'object' && + /^session\/[\da-z]+\/dataobj/.test(options.ajax.url) && !options.ajax.dataSrc) { + options.ajax.dataSrc = function(json) { + DT_rows_all = $.makeArray(json.DT_rows_all); + DT_rows_current = $.makeArray(json.DT_rows_current); + var data = json.data; + if (!colReorderEnabled()) return data; + var table = $table.DataTable(), order = table.colReorder.order(), flag = true, i, j, row; + for (i = 0; i < order.length; ++i) if (order[i] !== i) flag = false; + if (flag) return data; + for (i = 0; i < data.length; ++i) { + row = data[i].slice(); + for (j = 0; j < order.length; ++j) data[i][j] = row[order[j]]; + } + return data; + }; + } + + var thiz = this; + if (instance.fillContainer) $table.on('init.dt', function(e) { + thiz.fillAvailableHeight(el, $(el).innerHeight()); + }); + // If the page contains serveral datatables and one of which enables colReorder, + // the table.colReorder.order() function will exist but throws error when called. + // So it seems like the only way to know if colReorder is enabled or not is to + // check the options. + var colReorderEnabled = function() { return "colReorder" in options; }; + var table = $table.DataTable(options); + $el.data('datatable', table); + + if ('rowGroup' in options) { + // Maintain RowGroup dataSrc when columns are reordered (#1109) + table.on('column-reorder', function(e, settings, details) { + var oldDataSrc = table.rowGroup().dataSrc(); + var newDataSrc = details.mapping[oldDataSrc]; + table.rowGroup().dataSrc(newDataSrc); + }); + } + + // Unregister previous Crosstalk event subscriptions, if they exist + if (instance.ctfilterSubscription) { + instance.ctfilterHandle.off("change", instance.ctfilterSubscription); + instance.ctfilterSubscription = null; + } + if (instance.ctselectSubscription) { + instance.ctselectHandle.off("change", instance.ctselectSubscription); + instance.ctselectSubscription = null; + } + + if (!crosstalkOptions.group) { + $table[0].ctfilter = null; + $table[0].ctselect = null; + } else { + var key = crosstalkOptions.key; + function keysToMatches(keys) { + if (!keys) { + return null; + } else { + var selectedKeys = {}; + for (var i = 0; i < keys.length; i++) { + selectedKeys[keys[i]] = true; + } + var matches = {}; + for (var j = 0; j < key.length; j++) { + if (selectedKeys[key[j]]) + matches[j] = true; + } + return matches; + } + } + + function applyCrosstalkFilter(e) { + $table[0].ctfilter = keysToMatches(e.value); + table.draw(); + } + instance.ctfilterSubscription = instance.ctfilterHandle.on("change", applyCrosstalkFilter); + applyCrosstalkFilter({value: instance.ctfilterHandle.filteredKeys}); + + function applyCrosstalkSelection(e) { + if (e.sender !== instance.ctselectHandle) { + table + .rows('.' + selClass, {search: 'applied'}) + .nodes() + .to$() + .removeClass(selClass); + if (selectedRows) + changeInput('rows_selected', selectedRows(), void 0, true); + } + + if (e.sender !== instance.ctselectHandle && e.value && e.value.length) { + var matches = keysToMatches(e.value); + + // persistent selection with plotly (& leaflet) + var ctOpts = crosstalk.var("plotlyCrosstalkOpts").get() || {}; + if (ctOpts.persistent === true) { + var matches = $.extend(matches, $table[0].ctselect); + } + + $table[0].ctselect = matches; + table.draw(); + } else { + if ($table[0].ctselect) { + $table[0].ctselect = null; + table.draw(); + } + } + } + instance.ctselectSubscription = instance.ctselectHandle.on("change", applyCrosstalkSelection); + // TODO: This next line doesn't seem to work when renderDataTable is used + applyCrosstalkSelection({value: instance.ctselectHandle.value}); + } + + var inArray = function(val, array) { + return $.inArray(val, $.makeArray(array)) > -1; + }; + + // search the i-th column + var searchColumn = function(i, value) { + var regex = false, ci = true; + if (options.search) { + regex = options.search.regex, + ci = options.search.caseInsensitive !== false; + } + // need to transpose the column index when colReorder is enabled + if (table.colReorder) i = table.colReorder.transpose(i); + return table.column(i).search(value, regex, !regex, ci); + }; + + if (data.filter !== 'none') { + if (!data.hasOwnProperty('filterSettings')) data.filterSettings = {}; + + filterRow.each(function(i, td) { + + var $td = $(td), type = $td.data('type'), filter; + var $input = $td.children('div').first().children('input'); + var disabled = $input.prop('disabled'); + var searchable = table.settings()[0].aoColumns[i].bSearchable; + $input.prop('disabled', !searchable || disabled); + $input.data('searchable', searchable); // for updating later + $input.on('input blur', function() { + $input.next('span').toggle(Boolean($input.val())); + }); + // Bootstrap sets pointer-events to none and we won't be able to click + // the clear button + $input.next('span').css('pointer-events', 'auto').hide().click(function() { + $(this).hide().prev('input').val('').trigger('input').focus(); + }); + var searchCol; // search string for this column + if (searchCols && searchCols[i]) { + searchCol = searchCols[i]; + $input.val(searchCol).trigger('input'); + } + var $x = $td.children('div').last(); + + // remove the overflow: hidden attribute of the scrollHead + // (otherwise the scrolling table body obscures the filters) + // The workaround and the discussion from + // https://github.com/rstudio/DT/issues/554#issuecomment-518007347 + // Otherwise the filter selection will not be anchored to the values + // when the columns number is many and scrollX is enabled. + var scrollHead = $(el).find('.dataTables_scrollHead,.dataTables_scrollFoot'); + var cssOverflowHead = scrollHead.css('overflow'); + var scrollBody = $(el).find('.dataTables_scrollBody'); + var cssOverflowBody = scrollBody.css('overflow'); + var scrollTable = $(el).find('.dataTables_scroll'); + var cssOverflowTable = scrollTable.css('overflow'); + if (cssOverflowHead === 'hidden') { + $x.on('show hide', function(e) { + if (e.type === 'show') { + scrollHead.css('overflow', 'visible'); + scrollBody.css('overflow', 'visible'); + scrollTable.css('overflow-x', 'scroll'); + } else { + scrollHead.css('overflow', cssOverflowHead); + scrollBody.css('overflow', cssOverflowBody); + scrollTable.css('overflow-x', cssOverflowTable); + } + }); + $x.css('z-index', 25); + } + + if (inArray(type, ['factor', 'logical'])) { + $input.on({ + click: function() { + $input.parent().hide(); $x.show().trigger('show'); filter[0].selectize.focus(); + }, + input: function() { + var v1 = JSON.stringify(filter[0].selectize.getValue()), v2 = $input.val(); + if (v1 === '[]') v1 = ''; + if (v1 !== v2) filter[0].selectize.setValue(v2 === '' ? [] : JSON.parse(v2)); + } + }); + var $input2 = $x.children('select'); + filter = $input2.selectize($.extend({ + options: $input2.data('options').map(function(v, i) { + return ({text: v, value: v}); + }), + plugins: ['remove_button'], + hideSelected: true, + onChange: function(value) { + if (value === null) value = []; // compatibility with jQuery 3.0 + $input.val(value.length ? JSON.stringify(value) : ''); + if (value.length) $input.trigger('input'); + $input.attr('title', $input.val()); + if (server) { + searchColumn(i, value.length ? JSON.stringify(value) : '').draw(); + return; + } + // turn off filter if nothing selected + $td.data('filter', value.length > 0); + table.draw(); // redraw table, and filters will be applied + } + }, data.filterSettings.select)); + filter[0].selectize.on('blur', function() { + $x.hide().trigger('hide'); $input.parent().show(); $input.trigger('blur'); + }); + filter.next('div').css('margin-bottom', 'auto'); + } else if (type === 'character') { + var fun = function() { + searchColumn(i, $input.val()).draw(); + }; + // throttle searching for server-side processing + var throttledFun = $.fn.dataTable.util.throttle(fun, options.searchDelay); + $input.on('input', function(e, immediate) { + // always bypass throttling when immediate = true (via the updateSearch method) + (immediate || !server) ? fun() : throttledFun(); + }); + } else if (inArray(type, ['number', 'integer', 'date', 'time'])) { + var $x0 = $x; + $x = $x0.children('div').first(); + $x0.css({ + 'background-color': '#fff', + 'border': '1px #ddd solid', + 'border-radius': '4px', + 'padding': data.vertical ? '35px 20px': '20px 20px 10px 20px' + }); + var $spans = $x0.children('span').css({ + 'margin-top': data.vertical ? '0' : '10px', + 'white-space': 'nowrap' + }); + var $span1 = $spans.first(), $span2 = $spans.last(); + var r1 = +$x.data('min'), r2 = +$x.data('max'); + // when the numbers are too small or have many decimal places, the + // slider may have numeric precision problems (#150) + var scale = Math.pow(10, Math.max(0, +$x.data('scale') || 0)); + r1 = Math.round(r1 * scale); r2 = Math.round(r2 * scale); + var scaleBack = function(x, scale) { + if (scale === 1) return x; + var d = Math.round(Math.log(scale) / Math.log(10)); + // to avoid problems like 3.423/100 -> 0.034230000000000003 + return (x / scale).toFixed(d); + }; + var slider_min = function() { + return filter.noUiSlider('options').range.min; + }; + var slider_max = function() { + return filter.noUiSlider('options').range.max; + }; + $input.on({ + focus: function() { + $x0.show().trigger('show'); + // first, make sure the slider div leaves at least 20px between + // the two (slider value) span's + $x0.width(Math.max(160, $span1.outerWidth() + $span2.outerWidth() + 20)); + // then, if the input is really wide or slider is vertical, + // make the slider the same width as the input + if ($x0.outerWidth() < $input.outerWidth() || data.vertical) { + $x0.outerWidth($input.outerWidth()); + } + // make sure the slider div does not reach beyond the right margin + if ($(window).width() < $x0.offset().left + $x0.width()) { + $x0.offset({ + 'left': $input.offset().left + $input.outerWidth() - $x0.outerWidth() + }); + } + }, + blur: function() { + $x0.hide().trigger('hide'); + }, + input: function() { + if ($input.val() === '') filter.val([slider_min(), slider_max()]); + }, + change: function() { + var v = $input.val().replace(/\s/g, ''); + if (v === '') return; + v = v.split('...'); + if (v.length !== 2) { + $input.parent().addClass('has-error'); + return; + } + if (v[0] === '') v[0] = slider_min(); + if (v[1] === '') v[1] = slider_max(); + $input.parent().removeClass('has-error'); + // treat date as UTC time at midnight + var strTime = function(x) { + var s = type === 'date' ? 'T00:00:00Z' : ''; + var t = new Date(x + s).getTime(); + // add 10 minutes to date since it does not hurt the date, and + // it helps avoid the tricky floating point arithmetic problems, + // e.g. sometimes the date may be a few milliseconds earlier + // than the midnight due to precision problems in noUiSlider + return type === 'date' ? t + 3600000 : t; + }; + if (inArray(type, ['date', 'time'])) { + v[0] = strTime(v[0]); + v[1] = strTime(v[1]); + } + if (v[0] != slider_min()) v[0] *= scale; + if (v[1] != slider_max()) v[1] *= scale; + filter.val(v); + } + }); + var formatDate = function(d) { + d = scaleBack(d, scale); + if (type === 'number') return d; + if (type === 'integer') return parseInt(d); + var x = new Date(+d); + if (type === 'date') { + var pad0 = function(x) { + return ('0' + x).substr(-2, 2); + }; + return x.getUTCFullYear() + '-' + pad0(1 + x.getUTCMonth()) + + '-' + pad0(x.getUTCDate()); + } else { + return x.toISOString(); + } + }; + var opts = type === 'date' ? { step: 60 * 60 * 1000 } : + type === 'integer' ? { step: 1 } : {}; + + opts.orientation = data.vertical ? 'vertical': 'horizontal'; + opts.direction = data.vertical ? 'rtl': 'ltr'; + + filter = $x.noUiSlider($.extend({ + start: [r1, r2], + range: {min: r1, max: r2}, + connect: true + }, opts, data.filterSettings.slider)); + if (scale > 1) (function() { + var t1 = r1, t2 = r2; + var val = filter.val(); + while (val[0] > r1 || val[1] < r2) { + if (val[0] > r1) { + t1 -= val[0] - r1; + } + if (val[1] < r2) { + t2 += r2 - val[1]; + } + filter = $x.noUiSlider($.extend({ + start: [t1, t2], + range: {min: t1, max: t2}, + connect: true + }, opts, data.filterSettings.slider), true); + val = filter.val(); + } + r1 = t1; r2 = t2; + })(); + // format with active column renderer, if defined + var colDef = data.options.columnDefs.find(function(def) { + return (def.targets === i || inArray(i, def.targets)) && 'render' in def; + }); + var updateSliderText = function(v1, v2) { + // we only know how to use function renderers + if (colDef && typeof colDef.render === 'function') { + var restore = function(v) { + v = scaleBack(v, scale); + return inArray(type, ['date', 'time']) ? new Date(+v) : v; + } + $span1.text(colDef.render(restore(v1), 'display')); + $span2.text(colDef.render(restore(v2), 'display')); + } else { + $span1.text(formatDate(v1)); + $span2.text(formatDate(v2)); + } + }; + updateSliderText(r1, r2); + var updateSlider = function(e) { + var val = filter.val(); + // turn off filter if in full range + $td.data('filter', val[0] > slider_min() || val[1] < slider_max()); + var v1 = formatDate(val[0]), v2 = formatDate(val[1]), ival; + if ($td.data('filter')) { + ival = v1 + ' ... ' + v2; + $input.attr('title', ival).val(ival).trigger('input'); + } else { + $input.attr('title', '').val(''); + } + updateSliderText(val[0], val[1]); + if (e.type === 'slide') return; // no searching when sliding only + if (server) { + searchColumn(i, $td.data('filter') ? ival : '').draw(); + return; + } + table.draw(); + }; + filter.on({ + set: updateSlider, + slide: updateSlider + }); + } + + // server-side processing will be handled by R (or whatever server + // language you use); the following code is only needed for client-side + // processing + if (server) { + // if a search string has been pre-set, search now + if (searchCol) $input.trigger('input').trigger('change'); + return; + } + + var customFilter = function(settings, data, dataIndex) { + // there is no way to attach a search function to a specific table, + // and we need to make sure a global search function is not applied to + // all tables (i.e. a range filter in a previous table should not be + // applied to the current table); we use the settings object to + // determine if we want to perform searching on the current table, + // since settings.sTableId will be different to different tables + if (table.settings()[0] !== settings) return true; + // no filter on this column or no need to filter this column + if (typeof filter === 'undefined' || !$td.data('filter')) return true; + + var r = filter.val(), v, r0, r1; + var i_data = function(i) { + if (!colReorderEnabled()) return i; + var order = table.colReorder.order(), k; + for (k = 0; k < order.length; ++k) if (order[k] === i) return k; + return i; // in theory it will never be here... + } + v = data[i_data(i)]; + if (type === 'number' || type === 'integer') { + v = parseFloat(v); + // how to handle NaN? currently exclude these rows + if (isNaN(v)) return(false); + r0 = parseFloat(scaleBack(r[0], scale)) + r1 = parseFloat(scaleBack(r[1], scale)); + if (v >= r0 && v <= r1) return true; + } else if (type === 'date' || type === 'time') { + v = new Date(v); + r0 = new Date(r[0] / scale); r1 = new Date(r[1] / scale); + if (v >= r0 && v <= r1) return true; + } else if (type === 'factor') { + if (r.length === 0 || inArray(v, r)) return true; + } else if (type === 'logical') { + if (r.length === 0) return true; + if (inArray(v === '' ? 'na' : v, r)) return true; + } + return false; + }; + + $.fn.dataTable.ext.search.push(customFilter); + + // search for the preset search strings if it is non-empty + if (searchCol) $input.trigger('input').trigger('change'); + + }); + + } + + // highlight search keywords + var highlight = function() { + var body = $(table.table().body()); + // removing the old highlighting first + body.unhighlight(); + + // don't highlight the "not found" row, so we get the rows using the api + if (table.rows({ filter: 'applied' }).data().length === 0) return; + // highlight global search keywords + body.highlight($.trim(table.search()).split(/\s+/)); + // then highlight keywords from individual column filters + if (filterRow) filterRow.each(function(i, td) { + var $td = $(td), type = $td.data('type'); + if (type !== 'character') return; + var $input = $td.children('div').first().children('input'); + var column = table.column(i).nodes().to$(), + val = $.trim($input.val()); + if (type !== 'character' || val === '') return; + column.highlight(val.split(/\s+/)); + }); + }; + + if (options.searchHighlight) { + table + .on('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth', highlight) + .on('destroy', function() { + // remove event handler + table.off('draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'); + }); + + // Set the option for escaping regex characters in our search string. This will be used + // for all future matching. + jQuery.fn.highlight.options.escapeRegex = (!options.search || !options.search.regex); + + // initial highlight for state saved conditions and initial states + highlight(); + } + + // run the callback function on the table instance + if (typeof data.callback === 'function') data.callback(table); + + // double click to edit the cell, row, column, or all cells + if (data.editable) table.on('dblclick.dt', 'tbody td', function(e) { + // only bring up the editor when the cell itself is dbclicked, and ignore + // other dbclick events bubbled up (e.g. from the ) + if (e.target !== this) return; + var target = [], immediate = false; + switch (data.editable.target) { + case 'cell': + target = [this]; + immediate = true; // edit will take effect immediately + break; + case 'row': + target = table.cells(table.cell(this).index().row, '*').nodes(); + break; + case 'column': + target = table.cells('*', table.cell(this).index().column).nodes(); + break; + case 'all': + target = table.cells().nodes(); + break; + default: + throw 'The editable parameter must be "cell", "row", "column", or "all"'; + } + var disableCols = data.editable.disable ? data.editable.disable.columns : null; + var numericCols = data.editable.numeric; + var areaCols = data.editable.area; + var dateCols = data.editable.date; + for (var i = 0; i < target.length; i++) { + (function(cell, current) { + var $cell = $(cell), html = $cell.html(); + var _cell = table.cell(cell), value = _cell.data(), index = _cell.index().column; + var $input; + if (inArray(index, numericCols)) { + $input = $(''); + } else if (inArray(index, areaCols)) { + $input = $(''); + } else if (inArray(index, dateCols)) { + $input = $(''); + } else { + $input = $(''); + } + if (!immediate) { + $cell.data('input', $input).data('html', html); + $input.attr('title', 'Hit Ctrl+Enter to finish editing, or Esc to cancel'); + } + $input.val(value); + if (inArray(index, disableCols)) { + $input.attr('readonly', '').css('filter', 'invert(25%)'); + } + $cell.empty().append($input); + if (cell === current) $input.focus(); + $input.css('width', '100%'); + + if (immediate) $input.on('blur', function(e) { + var valueNew = $input.val(); + if (valueNew !== value) { + _cell.data(valueNew); + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', [cellInfo(cell)], 'DT.cellInfo', null, {priority: 'event'}); + } + // for server-side processing, users have to call replaceData() to update the table + if (!server) table.draw(false); + } else { + $cell.html(html); + } + }).on('keyup', function(e) { + // hit Escape to cancel editing + if (e.keyCode === 27) $input.trigger('blur'); + }); + + // bulk edit (row, column, or all) + if (!immediate) $input.on('keyup', function(e) { + var removeInput = function($cell, restore) { + $cell.data('input').remove(); + if (restore) $cell.html($cell.data('html')); + } + if (e.keyCode === 27) { + for (var i = 0; i < target.length; i++) { + removeInput($(target[i]), true); + } + } else if (e.keyCode === 13 && e.ctrlKey) { + // Ctrl + Enter + var cell, $cell, _cell, cellData = []; + for (var i = 0; i < target.length; i++) { + cell = target[i]; $cell = $(cell); _cell = table.cell(cell); + _cell.data($cell.data('input').val()); + HTMLWidgets.shinyMode && cellData.push(cellInfo(cell)); + removeInput($cell, false); + } + if (HTMLWidgets.shinyMode) { + changeInput('cell_edit', cellData, 'DT.cellInfo', null, {priority: "event"}); + } + if (!server) table.draw(false); + } + }); + })(target[i], this); + } + }); + + // interaction with shiny + if (!HTMLWidgets.shinyMode && !crosstalkOptions.group) return; + + var methods = {}; + var shinyData = {}; + + methods.updateCaption = function(caption) { + if (!caption) return; + $table.children('caption').replaceWith(caption); + } + + // register clear functions to remove input values when the table is removed + instance.clearInputs = {}; + + var changeInput = function(id, value, type, noCrosstalk, opts) { + var event = id; + id = el.id + '_' + id; + if (type) id = id + ':' + type; + // do not update if the new value is the same as old value + if (event !== 'cell_edit' && !/_clicked$/.test(event) && shinyData.hasOwnProperty(id) && shinyData[id] === JSON.stringify(value)) + return; + shinyData[id] = JSON.stringify(value); + if (HTMLWidgets.shinyMode && Shiny.setInputValue) { + Shiny.setInputValue(id, value, opts); + if (!instance.clearInputs[id]) instance.clearInputs[id] = function() { + Shiny.setInputValue(id, null); + } + } + + // HACK + if (event === "rows_selected" && !noCrosstalk) { + if (crosstalkOptions.group) { + var keys = crosstalkOptions.key; + var selectedKeys = null; + if (value) { + selectedKeys = []; + for (var i = 0; i < value.length; i++) { + // The value array's contents use 1-based row numbers, so we must + // convert to 0-based before indexing into the keys array. + selectedKeys.push(keys[value[i] - 1]); + } + } + instance.ctselectHandle.set(selectedKeys); + } + } + }; + + var addOne = function(x) { + return x.map(function(i) { return 1 + i; }); + }; + + var unique = function(x) { + var ux = []; + $.each(x, function(i, el){ + if ($.inArray(el, ux) === -1) ux.push(el); + }); + return ux; + } + + // change the row index of a cell + var tweakCellIndex = function(cell) { + var info = cell.index(); + // some cell may not be valid. e.g, #759 + // when using the RowGroup extension, datatables will + // generate the row label and the cells are not part of + // the data thus contain no row/col info + if (info === undefined) + return {row: null, col: null}; + if (server) { + info.row = DT_rows_current[info.row]; + } else { + info.row += 1; + } + return {row: info.row, col: info.column}; + } + + var cleanSelectedValues = function() { + changeInput('rows_selected', []); + changeInput('columns_selected', []); + changeInput('cells_selected', transposeArray2D([]), 'shiny.matrix'); + } + // #828 we should clean the selection on the server-side when the table reloads + cleanSelectedValues(); + + // a flag to indicates if select extension is initialized or not + var flagSelectExt = table.settings()[0]._select !== undefined; + // the Select extension should only be used in the client mode and + // when the selection.mode is set to none + if (data.selection.mode === 'none' && !server && flagSelectExt) { + var updateRowsSelected = function() { + var rows = table.rows({selected: true}); + var selected = []; + $.each(rows.indexes().toArray(), function(i, v) { + selected.push(v + 1); + }); + changeInput('rows_selected', selected); + } + var updateColsSelected = function() { + var columns = table.columns({selected: true}); + changeInput('columns_selected', columns.indexes().toArray()); + } + var updateCellsSelected = function() { + var cells = table.cells({selected: true}); + var selected = []; + cells.every(function() { + var row = this.index().row; + var col = this.index().column; + selected = selected.concat([[row + 1, col]]); + }); + changeInput('cells_selected', transposeArray2D(selected), 'shiny.matrix'); + } + table.on('select deselect', function(e, dt, type, indexes) { + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + }) + updateRowsSelected(); + updateColsSelected(); + updateCellsSelected(); + } + + var selMode = data.selection.mode, selTarget = data.selection.target; + var selDisable = data.selection.selectable === false; + if (inArray(selMode, ['single', 'multiple'])) { + var selClass = inArray(data.style, ['bootstrap', 'bootstrap4']) ? 'active' : 'selected'; + // selected1: row indices; selected2: column indices + var initSel = function(x) { + if (x === null || typeof x === 'boolean' || selTarget === 'cell') { + return {rows: [], cols: []}; + } else if (selTarget === 'row') { + return {rows: $.makeArray(x), cols: []}; + } else if (selTarget === 'column') { + return {rows: [], cols: $.makeArray(x)}; + } else if (selTarget === 'row+column') { + return {rows: $.makeArray(x.rows), cols: $.makeArray(x.cols)}; + } + } + var selected = data.selection.selected; + var selected1 = initSel(selected).rows, selected2 = initSel(selected).cols; + // selectable should contain either all positive or all non-positive values, not both + // positive values indicate "selectable" while non-positive values means "nonselectable" + // the assertion is performed on R side. (only column indicides could be zero which indicates + // the row name) + var selectable = data.selection.selectable; + var selectable1 = initSel(selectable).rows, selectable2 = initSel(selectable).cols; + + // After users reorder the rows or filter the table, we cannot use the table index + // directly. Instead, we need this function to find out the rows between the two clicks. + // If user filter the table again between the start click and the end click, the behavior + // would be undefined, but it should not be a problem. + var shiftSelRowsIndex = function(start, end) { + var indexes = server ? DT_rows_all : table.rows({ search: 'applied' }).indexes().toArray(); + start = indexes.indexOf(start); end = indexes.indexOf(end); + // if start is larger than end, we need to swap + if (start > end) { + var tmp = end; end = start; start = tmp; + } + return indexes.slice(start, end + 1); + } + + var serverRowIndex = function(clientRowIndex) { + return server ? DT_rows_current[clientRowIndex] : clientRowIndex + 1; + } + + // row, column, or cell selection + var lastClickedRow; + if (inArray(selTarget, ['row', 'row+column'])) { + // Get the current selected rows. It will also + // update the selected1's value based on the current row selection state + // Note we can't put this function inside selectRows() directly, + // the reason is method.selectRows() will override selected1's value but this + // function will add rows to selected1 (keep the existing selection), which is + // inconsistent with column and cell selection. + var selectedRows = function() { + var rows = table.rows('.' + selClass); + var idx = rows.indexes().toArray(); + if (!server) { + selected1 = addOne(idx); + return selected1; + } + idx = idx.map(function(i) { + return DT_rows_current[i]; + }); + selected1 = selMode === 'multiple' ? unique(selected1.concat(idx)) : idx; + return selected1; + } + // Change selected1's value based on selectable1, then refresh the row state + var onlyKeepSelectableRows = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected1 = []; + return; + } + if (selectable1.length === 0) return; + var nonselectable = selectable1[0] <= 0; + if (nonselectable) { + // should make selectable1 positive + selected1 = $(selected1).not(selectable1.map(function(i) { return -i; })).get(); + } else { + selected1 = $(selected1).filter(selectable1).get(); + } + } + // Change selected1's value based on selectable1, then + // refresh the row selection state according to values in selected1 + var selectRows = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableRows(); + table.$('tr.' + selClass).removeClass(selClass); + if (selected1.length === 0) return; + if (server) { + table.rows({page: 'current'}).every(function() { + if (inArray(DT_rows_current[this.index()], selected1)) { + $(this.node()).addClass(selClass); + } + }); + } else { + var selected0 = selected1.map(function(i) { return i - 1; }); + $(table.rows(selected0).nodes()).addClass(selClass); + } + } + table.on('mousedown.dt', 'tbody tr', function(e) { + var $this = $(this), thisRow = table.row(this); + if (selMode === 'multiple') { + if (e.shiftKey && lastClickedRow !== undefined) { + // select or de-select depends on the last clicked row's status + var flagSel = !$this.hasClass(selClass); + var crtClickedRow = serverRowIndex(thisRow.index()); + if (server) { + var rowsIndex = shiftSelRowsIndex(lastClickedRow, crtClickedRow); + // update current page's selClass + rowsIndex.map(function(i) { + var rowIndex = DT_rows_current.indexOf(i); + if (rowIndex >= 0) { + var row = table.row(rowIndex).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + } + }); + // update selected1 + if (flagSel) { + selected1 = unique(selected1.concat(rowsIndex)); + } else { + selected1 = selected1.filter(function(index) { + return !inArray(index, rowsIndex); + }); + } + } else { + // js starts from 0 + shiftSelRowsIndex(lastClickedRow - 1, crtClickedRow - 1).map(function(value) { + var row = table.row(value).nodes().to$(); + var flagRowSel = !row.hasClass(selClass); + if (flagSel === flagRowSel) row.toggleClass(selClass); + }); + } + e.preventDefault(); + } else { + $this.toggleClass(selClass); + } + } else { + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + } else { + table.$('tr.' + selClass).removeClass(selClass); + $this.addClass(selClass); + } + } + if (server && !$this.hasClass(selClass)) { + var id = DT_rows_current[thisRow.index()]; + // remove id from selected1 since its class .selected has been removed + if (inArray(id, selected1)) selected1.splice($.inArray(id, selected1), 1); + } + selectedRows(); // update selected1's value based on selClass + selectRows(false); // only keep the selectable rows + changeInput('rows_selected', selected1); + changeInput('row_last_clicked', serverRowIndex(thisRow.index()), null, null, {priority: 'event'}); + lastClickedRow = serverRowIndex(thisRow.index()); + }); + selectRows(false); // in case users have specified pre-selected rows + // restore selected rows after the table is redrawn (e.g. sort/search/page); + // client-side tables will preserve the selections automatically; for + // server-side tables, we have to *real* row indices are in `selected1` + changeInput('rows_selected', selected1); + if (server) table.on('draw.dt', function(e) { selectRows(false); }); + methods.selectRows = function(selected, ignoreSelectable) { + selected1 = $.makeArray(selected); + selectRows(ignoreSelectable); + changeInput('rows_selected', selected1); + } + } + + if (inArray(selTarget, ['column', 'row+column'])) { + if (selTarget === 'row+column') { + $(table.columns().footer()).css('cursor', 'pointer'); + } + // update selected2's value based on selectable2 + var onlyKeepSelectableCols = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected2 = []; + return; + } + if (selectable2.length === 0) return; + var nonselectable = selectable2[0] <= 0; + if (nonselectable) { + // need to make selectable2 positive + selected2 = $(selected2).not(selectable2.map(function(i) { return -i; })).get(); + } else { + selected2 = $(selected2).filter(selectable2).get(); + } + } + // update selected2 and then + // refresh the col selection state according to values in selected2 + var selectCols = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCols(); + // if selected2 is not a valide index (e.g., larger than the column number) + // table.columns(selected2) will fail and result in a blank table + // this is different from the table.rows(), where the out-of-range indexes + // doesn't affect at all + selected2 = $(selected2).filter(table.columns().indexes()).get(); + table.columns().nodes().flatten().to$().removeClass(selClass); + if (selected2.length > 0) + table.columns(selected2).nodes().flatten().to$().addClass(selClass); + } + var callback = function() { + var colIdx = selTarget === 'column' ? table.cell(this).index().column : + $.inArray(this, table.columns().footer()), + thisCol = $(table.column(colIdx).nodes()); + if (colIdx === -1) return; + if (thisCol.hasClass(selClass)) { + thisCol.removeClass(selClass); + selected2.splice($.inArray(colIdx, selected2), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + thisCol.addClass(selClass); + selected2 = selMode === 'single' ? [colIdx] : unique(selected2.concat([colIdx])); + } + selectCols(false); // update selected2 based on selectable + changeInput('columns_selected', selected2); + } + if (selTarget === 'column') { + $(table.table().body()).on('click.dt', 'td', callback); + } else { + $(table.table().footer()).on('click.dt', 'tr th', callback); + } + selectCols(false); // in case users have specified pre-selected columns + changeInput('columns_selected', selected2); + if (server) table.on('draw.dt', function(e) { selectCols(false); }); + methods.selectColumns = function(selected, ignoreSelectable) { + selected2 = $.makeArray(selected); + selectCols(ignoreSelectable); + changeInput('columns_selected', selected2); + } + } + + if (selTarget === 'cell') { + var selected3 = [], selectable3 = []; + if (selected !== null) selected3 = selected; + if (selectable !== null && typeof selectable !== 'boolean') selectable3 = selectable; + var findIndex = function(ij, sel) { + for (var i = 0; i < sel.length; i++) { + if (ij[0] === sel[i][0] && ij[1] === sel[i][1]) return i; + } + return -1; + } + // Change selected3's value based on selectable3, then refresh the cell state + var onlyKeepSelectableCells = function() { + if (selDisable) { // users can't select; useful when only want backend select + selected3 = []; + return; + } + if (selectable3.length === 0) return; + var nonselectable = selectable3[0][0] <= 0; + var out = []; + if (nonselectable) { + selected3.map(function(ij) { + // should make selectable3 positive + if (findIndex([-ij[0], -ij[1]], selectable3) === -1) { out.push(ij); } + }); + } else { + selected3.map(function(ij) { + if (findIndex(ij, selectable3) > -1) { out.push(ij); } + }); + } + selected3 = out; + } + // Change selected3's value based on selectable3, then + // refresh the cell selection state according to values in selected3 + var selectCells = function(ignoreSelectable) { + if (!ignoreSelectable) onlyKeepSelectableCells(); + table.$('td.' + selClass).removeClass(selClass); + if (selected3.length === 0) return; + if (server) { + table.cells({page: 'current'}).every(function() { + var info = tweakCellIndex(this); + if (findIndex([info.row, info.col], selected3) > -1) + $(this.node()).addClass(selClass); + }); + } else { + selected3.map(function(ij) { + $(table.cell(ij[0] - 1, ij[1]).node()).addClass(selClass); + }); + } + }; + table.on('click.dt', 'tbody td', function() { + var $this = $(this), info = tweakCellIndex(table.cell(this)); + if ($this.hasClass(selClass)) { + $this.removeClass(selClass); + selected3.splice(findIndex([info.row, info.col], selected3), 1); + } else { + if (selMode === 'single') $(table.cells().nodes()).removeClass(selClass); + $this.addClass(selClass); + selected3 = selMode === 'single' ? [[info.row, info.col]] : + unique(selected3.concat([[info.row, info.col]])); + } + selectCells(false); // must call this to update selected3 based on selectable3 + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + }); + selectCells(false); // in case users have specified pre-selected columns + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + + if (server) table.on('draw.dt', function(e) { selectCells(false); }); + methods.selectCells = function(selected, ignoreSelectable) { + selected3 = selected ? selected : []; + selectCells(ignoreSelectable); + changeInput('cells_selected', transposeArray2D(selected3), 'shiny.matrix'); + } + } + } + + // expose some table info to Shiny + var updateTableInfo = function(e, settings) { + // TODO: is anyone interested in the page info? + // changeInput('page_info', table.page.info()); + var updateRowInfo = function(id, modifier) { + var idx; + if (server) { + idx = modifier.page === 'current' ? DT_rows_current : DT_rows_all; + } else { + var rows = table.rows($.extend({ + search: 'applied', + page: 'all' + }, modifier)); + idx = addOne(rows.indexes().toArray()); + } + changeInput('rows' + '_' + id, idx); + }; + updateRowInfo('current', {page: 'current'}); + updateRowInfo('all', {}); + } + table.on('draw.dt', updateTableInfo); + updateTableInfo(); + + // state info + table.on('draw.dt column-visibility.dt', function() { + changeInput('state', table.state()); + }); + changeInput('state', table.state()); + + // search info + var updateSearchInfo = function() { + changeInput('search', table.search()); + if (filterRow) changeInput('search_columns', filterRow.toArray().map(function(td) { + return $(td).find('input').first().val(); + })); + } + table.on('draw.dt', updateSearchInfo); + updateSearchInfo(); + + var cellInfo = function(thiz) { + var info = tweakCellIndex(table.cell(thiz)); + info.value = table.cell(thiz).data(); + return info; + } + // the current cell clicked on + table.on('click.dt', 'tbody td', function() { + changeInput('cell_clicked', cellInfo(this), null, null, {priority: 'event'}); + }) + changeInput('cell_clicked', {}); + + // do not trigger table selection when clicking on links unless they have classes + table.on('mousedown.dt', 'tbody td a', function(e) { + if (this.className === '') e.stopPropagation(); + }); + + methods.addRow = function(data, rowname, resetPaging) { + var n = table.columns().indexes().length, d = n - data.length; + if (d === 1) { + data = rowname.concat(data) + } else if (d !== 0) { + console.log(data); + console.log(table.columns().indexes()); + throw 'New data must be of the same length as current data (' + n + ')'; + }; + table.row.add(data).draw(resetPaging); + } + + methods.updateSearch = function(keywords) { + if (keywords.global !== null) + $(table.table().container()).find('input[type=search]').first() + .val(keywords.global).trigger('input'); + var columns = keywords.columns; + if (!filterRow || columns === null) return; + filterRow.toArray().map(function(td, i) { + var v = typeof columns === 'string' ? columns : columns[i]; + if (typeof v === 'undefined') { + console.log('The search keyword for column ' + i + ' is undefined') + return; + } + // Update column search string and values on linked filter widgets. + // 'input' for factor and char filters, 'change' for numeric filters. + $(td).find('input').first().val(v).trigger('input', [true]).trigger('change'); + }); + table.draw(); + } + + methods.hideCols = function(hide, reset) { + if (reset) table.columns().visible(true, false); + table.columns(hide).visible(false); + } + + methods.showCols = function(show, reset) { + if (reset) table.columns().visible(false, false); + table.columns(show).visible(true); + } + + methods.colReorder = function(order, origOrder) { + table.colReorder.order(order, origOrder); + } + + methods.selectPage = function(page) { + if (table.page.info().pages < page || page < 1) { + throw 'Selected page is out of range'; + }; + table.page(page - 1).draw(false); + } + + methods.reloadData = function(resetPaging, clearSelection) { + // empty selections first if necessary + if (methods.selectRows && inArray('row', clearSelection)) methods.selectRows([]); + if (methods.selectColumns && inArray('column', clearSelection)) methods.selectColumns([]); + if (methods.selectCells && inArray('cell', clearSelection)) methods.selectCells([]); + table.ajax.reload(null, resetPaging); + } + + // update table filters (set new limits of sliders) + methods.updateFilters = function(newProps) { + // loop through each filter in the filter row + filterRow.each(function(i, td) { + var k = i; + if (filterRow.length > newProps.length) { + if (i === 0) return; // first column is row names + k = i - 1; + } + // Update the filters to reflect the updated data. + // Allow "falsy" (e.g. NULL) to signify a no-op. + if (newProps[k]) { + setFilterProps(td, newProps[k]); + } + }); + }; + + table.shinyMethods = methods; + }, + resize: function(el, width, height, instance) { + if (instance.data) this.renderValue(el, instance.data, instance); + + // dynamically adjust height if fillContainer = TRUE + if (instance.fillContainer) + this.fillAvailableHeight(el, height); + + this.adjustWidth(el); + }, + + // dynamically set the scroll body to fill available height + // (used with fillContainer = TRUE) + fillAvailableHeight: function(el, availableHeight) { + + // see how much of the table is occupied by header/footer elements + // and use that to compute a target scroll body height + var dtWrapper = $(el).find('div.dataTables_wrapper'); + var dtScrollBody = $(el).find($('div.dataTables_scrollBody')); + var framingHeight = dtWrapper.innerHeight() - dtScrollBody.innerHeight(); + var scrollBodyHeight = availableHeight - framingHeight; + + // we need to set `max-height` to none as datatables library now sets this + // to a fixed height, disabling the ability to resize to fill the window, + // as it will be set to a fixed 100px under such circumstances, e.g., RStudio IDE, + // or FlexDashboard + // see https://github.com/rstudio/DT/issues/951#issuecomment-1026464509 + dtScrollBody.css('max-height', 'none'); + // set the height + dtScrollBody.height(scrollBodyHeight + 'px'); + }, + + // adjust the width of columns; remove the hard-coded widths on table and the + // scroll header when scrollX/Y are enabled + adjustWidth: function(el) { + var $el = $(el), table = $el.data('datatable'); + if (table) table.columns.adjust(); + $el.find('.dataTables_scrollHeadInner').css('width', '') + .children('table').css('margin-left', ''); + } +}); + + if (!HTMLWidgets.shinyMode) return; + + Shiny.addCustomMessageHandler('datatable-calls', function(data) { + var id = data.id; + var el = document.getElementById(id); + var table = el ? $(el).data('datatable') : null; + if (!table) { + console.log("Couldn't find table with id " + id); + return; + } + + var methods = table.shinyMethods, call = data.call; + if (methods[call.method]) { + methods[call.method].apply(table, call.args); + } else { + console.log("Unknown method " + call.method); + } + }); + +})(); diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-css/datatables-crosstalk.css b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-css/datatables-crosstalk.css new file mode 100644 index 0000000..bd1159c --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/datatables-css/datatables-crosstalk.css @@ -0,0 +1,32 @@ +.dt-crosstalk-fade { + opacity: 0.2; +} + +html body div.DTS div.dataTables_scrollBody { + background: none; +} + + +/* +Fix https://github.com/rstudio/DT/issues/563 +If the `table.display` is set to "block" (e.g., pkgdown), the browser will display +datatable objects strangely. The search panel and the page buttons will still be +in full-width but the table body will be "compact" and shorter. +In therory, having this attributes will affect `dom="t"` +with `display: block` users. But in reality, there should be no one. +We may remove the below lines in the future if the upstream agree to have this there. +See https://github.com/DataTables/DataTablesSrc/issues/160 +*/ + +table.dataTable { + display: table; +} + + +/* +When DTOutput(fill = TRUE), it receives a .html-fill-item class (via htmltools::bindFillRole()), which effectively amounts to `flex: 1 1 auto`. That's mostly fine, but the case where `fillContainer=TRUE`+`height:auto`+`flex-basis:auto` and the container (e.g., a bslib::card()) doesn't have a defined height is a bit problematic since the table wants to fit the parent but the parent wants to fit the table, which results pretty small table height (maybe because there is a minimum height somewhere?). It seems better in this case to impose a 400px height default for the table, which we can do by setting `flex-basis` to 400px (the table is still allowed to grow/shrink when the container has an opinionated height). +*/ + +.html-fill-container > .html-fill-item.datatables { + flex-basis: 400px; +} diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.extra.css b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.extra.css new file mode 100644 index 0000000..b2dd141 --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.extra.css @@ -0,0 +1,28 @@ +/* Selected rows/cells */ +table.dataTable tr.selected td, table.dataTable td.selected { + background-color: #b0bed9 !important; +} +/* In case of scrollX/Y or FixedHeader */ +.dataTables_scrollBody .dataTables_sizing { + visibility: hidden; +} + +/* The datatables' theme CSS file doesn't define +the color but with white background. It leads to an issue that +when the HTML's body color is set to 'white', the user can't +see the text since the background is white. One case happens in the +RStudio's IDE when inline viewing the DT table inside an Rmd file, +if the IDE theme is set to "Cobalt". + +See https://github.com/rstudio/DT/issues/447 for more info + +This fixes should have little side-effects because all the other elements +of the default theme use the #333 font color. + +TODO: The upstream may use relative colors for both the table background +and the color. It means the table can display well without this patch +then. At that time, we need to remove the below CSS attributes. +*/ +div.datatables { + color: #333; +} diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.min.css b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.min.css new file mode 100644 index 0000000..ad59f84 --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/css/jquery.dataTables.min.css @@ -0,0 +1 @@ +:root{--dt-row-selected: 13, 110, 253;--dt-row-selected-text: 255, 255, 255;--dt-row-selected-link: 9, 10, 11;--dt-row-stripe: 0, 0, 0;--dt-row-hover: 0, 0, 0;--dt-column-ordering: 0, 0, 0;--dt-html-background: white}:root.dark{--dt-html-background: rgb(33, 37, 41)}table.dataTable td.dt-control{text-align:center;cursor:pointer}table.dataTable td.dt-control:before{display:inline-block;color:rgba(0, 0, 0, 0.5);content:"►"}table.dataTable tr.dt-hasChild td.dt-control:before{content:"▼"}html.dark table.dataTable td.dt-control:before{color:rgba(255, 255, 255, 0.5)}html.dark table.dataTable tr.dt-hasChild td.dt-control:before{color:rgba(255, 255, 255, 0.5)}table.dataTable thead>tr>th.sorting,table.dataTable thead>tr>th.sorting_asc,table.dataTable thead>tr>th.sorting_desc,table.dataTable thead>tr>th.sorting_asc_disabled,table.dataTable thead>tr>th.sorting_desc_disabled,table.dataTable thead>tr>td.sorting,table.dataTable thead>tr>td.sorting_asc,table.dataTable thead>tr>td.sorting_desc,table.dataTable thead>tr>td.sorting_asc_disabled,table.dataTable thead>tr>td.sorting_desc_disabled{cursor:pointer;position:relative;padding-right:26px}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after{position:absolute;display:block;opacity:.125;right:10px;line-height:9px;font-size:.8em}table.dataTable thead>tr>th.sorting:before,table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:before,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>th.sorting_desc_disabled:before,table.dataTable thead>tr>td.sorting:before,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:before,table.dataTable thead>tr>td.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:before{bottom:50%;content:"▲";content:"▲"/""}table.dataTable thead>tr>th.sorting:after,table.dataTable thead>tr>th.sorting_asc:after,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>th.sorting_asc_disabled:after,table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting:after,table.dataTable thead>tr>td.sorting_asc:after,table.dataTable thead>tr>td.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc_disabled:after,table.dataTable thead>tr>td.sorting_desc_disabled:after{top:50%;content:"▼";content:"▼"/""}table.dataTable thead>tr>th.sorting_asc:before,table.dataTable thead>tr>th.sorting_desc:after,table.dataTable thead>tr>td.sorting_asc:before,table.dataTable thead>tr>td.sorting_desc:after{opacity:.6}table.dataTable thead>tr>th.sorting_desc_disabled:after,table.dataTable thead>tr>th.sorting_asc_disabled:before,table.dataTable thead>tr>td.sorting_desc_disabled:after,table.dataTable thead>tr>td.sorting_asc_disabled:before{display:none}table.dataTable thead>tr>th:active,table.dataTable thead>tr>td:active{outline:none}div.dataTables_scrollBody>table.dataTable>thead>tr>th:before,div.dataTables_scrollBody>table.dataTable>thead>tr>th:after,div.dataTables_scrollBody>table.dataTable>thead>tr>td:before,div.dataTables_scrollBody>table.dataTable>thead>tr>td:after{display:none}div.dataTables_processing{position:absolute;top:50%;left:50%;width:200px;margin-left:-100px;margin-top:-26px;text-align:center;padding:2px}div.dataTables_processing>div:last-child{position:relative;width:80px;height:15px;margin:1em auto}div.dataTables_processing>div:last-child>div{position:absolute;top:0;width:13px;height:13px;border-radius:50%;background:rgb(13, 110, 253);background:rgb(var(--dt-row-selected));animation-timing-function:cubic-bezier(0, 1, 1, 0)}div.dataTables_processing>div:last-child>div:nth-child(1){left:8px;animation:datatables-loader-1 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(2){left:8px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(3){left:32px;animation:datatables-loader-2 .6s infinite}div.dataTables_processing>div:last-child>div:nth-child(4){left:56px;animation:datatables-loader-3 .6s infinite}@keyframes datatables-loader-1{0%{transform:scale(0)}100%{transform:scale(1)}}@keyframes datatables-loader-3{0%{transform:scale(1)}100%{transform:scale(0)}}@keyframes datatables-loader-2{0%{transform:translate(0, 0)}100%{transform:translate(24px, 0)}}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th,table.dataTable thead td,table.dataTable tfoot th,table.dataTable tfoot td{text-align:left}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable>thead>tr>th,table.dataTable>thead>tr>td{padding:10px;border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable>thead>tr>th:active,table.dataTable>thead>tr>td:active{outline:none}table.dataTable>tfoot>tr>th,table.dataTable>tfoot>tr>td{padding:10px 10px 6px 10px;border-top:1px solid rgba(0, 0, 0, 0.3)}table.dataTable tbody tr{background-color:transparent}table.dataTable tbody tr.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.9);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.9);color:rgb(255, 255, 255);color:rgb(var(--dt-row-selected-text))}table.dataTable tbody tr.selected a{color:rgb(9, 10, 11);color:rgb(var(--dt-row-selected-link))}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border>tbody>tr>th,table.dataTable.row-border>tbody>tr>td,table.dataTable.display>tbody>tr>th,table.dataTable.display>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.row-border>tbody>tr:first-child>th,table.dataTable.row-border>tbody>tr:first-child>td,table.dataTable.display>tbody>tr:first-child>th,table.dataTable.display>tbody>tr:first-child>td{border-top:none}table.dataTable.row-border>tbody>tr.selected+tr.selected>td,table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0262ef}table.dataTable.cell-border>tbody>tr>th,table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgba(0, 0, 0, 0.15);border-right:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr>th:first-child,table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgba(0, 0, 0, 0.15)}table.dataTable.cell-border>tbody>tr:first-child>th,table.dataTable.cell-border>tbody>tr:first-child>td{border-top:none}table.dataTable.stripe>tbody>tr.odd>*,table.dataTable.display>tbody>tr.odd>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.023);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.023)}table.dataTable.stripe>tbody>tr.odd.selected>*,table.dataTable.display>tbody>tr.odd.selected>*{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.923);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.923)}table.dataTable.hover>tbody>tr:hover>*,table.dataTable.display>tbody>tr:hover>*{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.035);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.035)}table.dataTable.hover>tbody>tr.selected:hover>*,table.dataTable.display>tbody>tr.selected:hover>*{box-shadow:inset 0 0 0 9999px #0d6efd !important;box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 1) !important}table.dataTable.order-column>tbody tr>.sorting_1,table.dataTable.order-column>tbody tr>.sorting_2,table.dataTable.order-column>tbody tr>.sorting_3,table.dataTable.display>tbody tr>.sorting_1,table.dataTable.display>tbody tr>.sorting_2,table.dataTable.display>tbody tr>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.019)}table.dataTable.order-column>tbody tr.selected>.sorting_1,table.dataTable.order-column>tbody tr.selected>.sorting_2,table.dataTable.order-column>tbody tr.selected>.sorting_3,table.dataTable.display>tbody tr.selected>.sorting_1,table.dataTable.display>tbody tr.selected>.sorting_2,table.dataTable.display>tbody tr.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.odd>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.054);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.054)}table.dataTable.display>tbody>tr.odd>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.047);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.047)}table.dataTable.display>tbody>tr.odd>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.039);box-shadow:inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.039)}table.dataTable.display>tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.954);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.954)}table.dataTable.display>tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.947);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.947)}table.dataTable.display>tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.odd.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.939);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.939)}table.dataTable.display>tbody>tr.even>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.019);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.019)}table.dataTable.display>tbody>tr.even>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.011);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.011)}table.dataTable.display>tbody>tr.even>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.003);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.003)}table.dataTable.display>tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.919);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919)}table.dataTable.display>tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.911);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.911)}table.dataTable.display>tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe>tbody>tr.even.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.903);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.903)}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.082);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.082)}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.074);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.074)}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(0, 0, 0, 0.062);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.062)}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.982);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.982)}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.974);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.974)}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{box-shadow:inset 0 0 0 9999px rgba(13, 110, 253, 0.962);box-shadow:inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.962)}table.dataTable.no-footer{border-bottom:1px solid rgba(0, 0, 0, 0.3)}table.dataTable.compact thead th,table.dataTable.compact thead td,table.dataTable.compact tfoot th,table.dataTable.compact tfoot td,table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_length select{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;padding:4px}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{border:1px solid #aaa;border-radius:3px;padding:5px;background-color:transparent;color:inherit;margin-left:3px}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;color:inherit !important;border:1px solid transparent;border-radius:2px;background:transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:inherit !important;border:1px solid rgba(0, 0, 0, 0.3);background-color:rgba(0, 0, 0, 0.05);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.05)), color-stop(100%, rgba(0, 0, 0, 0.05)));background:-webkit-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-moz-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-ms-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:-o-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#111;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#0c0c0c;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:inherit}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid rgba(0, 0, 0, 0.3)}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:.5em}}html.dark{--dt-row-hover: 255, 255, 255;--dt-row-stripe: 255, 255, 255;--dt-column-ordering: 255, 255, 255}html.dark table.dataTable>thead>tr>th,html.dark table.dataTable>thead>tr>td{border-bottom:1px solid rgb(89, 91, 94)}html.dark table.dataTable>thead>tr>th:active,html.dark table.dataTable>thead>tr>td:active{outline:none}html.dark table.dataTable>tfoot>tr>th,html.dark table.dataTable>tfoot>tr>td{border-top:1px solid rgb(89, 91, 94)}html.dark table.dataTable.row-border>tbody>tr>th,html.dark table.dataTable.row-border>tbody>tr>td,html.dark table.dataTable.display>tbody>tr>th,html.dark table.dataTable.display>tbody>tr>td{border-top:1px solid rgb(64, 67, 70)}html.dark table.dataTable.row-border>tbody>tr.selected+tr.selected>td,html.dark table.dataTable.display>tbody>tr.selected+tr.selected>td{border-top-color:#0257d5}html.dark table.dataTable.cell-border>tbody>tr>th,html.dark table.dataTable.cell-border>tbody>tr>td{border-top:1px solid rgb(64, 67, 70);border-right:1px solid rgb(64, 67, 70)}html.dark table.dataTable.cell-border>tbody>tr>th:first-child,html.dark table.dataTable.cell-border>tbody>tr>td:first-child{border-left:1px solid rgb(64, 67, 70)}html.dark .dataTables_wrapper .dataTables_filter input,html.dark .dataTables_wrapper .dataTables_length select{border:1px solid rgba(255, 255, 255, 0.2);background-color:var(--dt-html-background)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{border:1px solid rgb(89, 91, 94);background:rgba(255, 255, 255, 0.15)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,html.dark .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{color:#666 !important}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:hover{border:1px solid rgb(53, 53, 53);background:rgb(53, 53, 53)}html.dark .dataTables_wrapper .dataTables_paginate .paginate_button:active{background:#3a3a3a} diff --git a/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/js/jquery.dataTables.min.js b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/js/jquery.dataTables.min.js new file mode 100644 index 0000000..f786b0d --- /dev/null +++ b/public/2024/07/strength-in-data-connecting-to-the-taskmaster-database/index_files/dt-core/js/jquery.dataTables.min.js @@ -0,0 +1,4 @@ +/*! DataTables 1.13.6 + * ©2008-2023 SpryMedia Ltd - datatables.net/license + */ +!function(n){"use strict";var a;"function"==typeof define&&define.amd?define(["jquery"],function(t){return n(t,window,document)}):"object"==typeof exports?(a=require("jquery"),"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||a(t),n(e,t,t.document)}:n(a,window,window.document)):window.DataTable=n(jQuery,window,document)}(function(P,j,v,H){"use strict";function d(t){var e=parseInt(t,10);return!isNaN(e)&&isFinite(t)?e:null}function l(t,e,n){var a=typeof t,r="string"==a;return"number"==a||"bigint"==a||!!h(t)||(e&&r&&(t=$(t,e)),n&&r&&(t=t.replace(q,"")),!isNaN(parseFloat(t))&&isFinite(t))}function a(t,e,n){var a;return!!h(t)||(h(a=t)||"string"==typeof a)&&!!l(t.replace(V,"").replace(/ + + 404 Page not found - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

404 NOT FOUND

+
+
+ + + \ No newline at end of file diff --git a/public/_index.Rmd b/public/_index.Rmd new file mode 100644 index 0000000..e9bfd33 --- /dev/null +++ b/public/_index.Rmd @@ -0,0 +1,23 @@ +--- +title: The Median Duck Home Page +author: Christopher Nam +editor_options: + markdown: + wrap: 72 +--- + +# Welcome! + +![](img/duck_tt.png) + +Welcome to The Median Duck, a self initiated project that aims to +educate and entertain the general public on data analytic topics through +the hit UK TV show [Taskmaster](https://en.wikipedia.org/wiki/Taskmaster_(TV_series)). + +This project is in its early stages, but great things are planned; see +this [vision document](vision) for the ambitious plans that I have in mind. + +> **Your Time Starts Now!** + +------------------------------------------------------------------------ + diff --git a/public/about-hugo/index.html b/public/about-hugo/index.html new file mode 100644 index 0000000..a6eee06 --- /dev/null +++ b/public/about-hugo/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:4321/themedianduck/about/ + + + + + + diff --git a/public/about-me/index.html b/public/about-me/index.html new file mode 100644 index 0000000..f3415d4 --- /dev/null +++ b/public/about-me/index.html @@ -0,0 +1,10 @@ + + + + //localhost:4321/about/ + + + + + + diff --git a/public/about-us/index.html b/public/about-us/index.html new file mode 100644 index 0000000..a6eee06 --- /dev/null +++ b/public/about-us/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:4321/themedianduck/about/ + + + + + + diff --git a/public/about/index.html b/public/about/index.html new file mode 100644 index 0000000..6772471 --- /dev/null +++ b/public/about/index.html @@ -0,0 +1,158 @@ + + + + About Me - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

About Me

+
Posted on Jul 8, 2024
+
+ + + + +
+

My Professional Background

+

I obtained a PhD in Statistics from the University of Warwick in 2013, my thesis title was “Uncertainty in Changepoints in Time Series” 1. I’m delighted that Dr Little Alex Horne recently became associated with my alma mater through the Taskmaster Education scheme.

+

I have 10 years of industry experience as a Research Scientist/Data Scientist at Amazon and Samsung, predominantly demand forecasting at scale for products. From this experience, I have some experience on running projects at scale, with rigor (automation, repeatability) and compromises that need to be made (whether it be technical, monetary, mental).

+

My Personal Motivation

+

There are a variety of personal reasons why I am starting The Median Duck.

+

Perhaps optimistically, I want to (stealthy) educate others of analytics to the general public in a fun and amusing manner. Statistics is not taught particularly well in the UK, often seen as a boring number crunching and often a medium to lie. Add to this, I want to instill best practices and the graft work that I have experienced over my years, and that are often overlooked in courses and textbooks (importance of good quality data, automated workflows, etc.).

+

I made the somewhat brave decision to become self employed at the start of 2024, and have various ventures in the work to provide some income and keep me entertained on a daily basis (piano teaching, piano performance, admin for my housing association). The Median Duck is one of these ventures.

+

I don’t expect this venture to be a money maker (major or minor), but I do want to retain my engagement in the data science and statistics field. Add to this, my “imposter syndrome” often wants me to relearn the basics.

+

I do have some aspirations to potentially go into data journalism through data science and analytics and this venture may provide some experience and build up a portfolio of work.

+

Finally, I do not claim to be a full expert and entirely knowledgeable about the analysis I will be covering2. However I’m always eager to learn new topics and also educate others; I believe I am an educator and teacher at my core. My passion for Taskmaster and prior experience with the analytics field thus makes The Median Duck this the ideal vehicle.

+

My Taskmaster Journey

+

My Taskmaster journey properly started during 2020 (and the global pandemic), when the Series 2 task “order something without using certain words” was recommended to me on YouTube. Once I watched this task, I was hooked and consequently went down the Taskmaster rabbit hole and binged whatever series were available.

+

However, prior to this, I was initially quite dismissive of Taskmaster. I had previously associated “Taskmaster” with “Ticketmaster” and thus erroneously thought it was going to be a dull show in which extortionate ticket scalping would occur. How wrong I was…

+

Since 2020, I have watched each series of Taskmaster (mainly UK) near the time of broadcast, and consumed Taskmaster adjacent material (the podcast, comedians appearances on other comedy shows etc.).

+

I have also unofficially (and jokingly) assigned myself the title of “Taskmaster Representative of the Pacific Northwest” as I have referred numerous friends and colleagues about Taskmaster and also informed them of when the next series is broadcasting.

+

These are a Few of My Favourite Taskmaster Things…

+
    +
  • Favourite Task: Ringtone Choreography (S4E4)
  • +
  • Favourite Series: Series 4 or 5.
  • +
  • Favourite Contestant: Victoria Coren Mitchell3
  • +
  • Favourite Quote(s): “Friendship is Truth”
  • +
  • Degrees of Separation to Alex Horne (to my knowledge): 3
  • +
+
+
+
    +
  1. +

    I’m sure you eager readers can find my thesis online and be gently amused by my chapter quotes. ↩︎

    +
  2. +
  3. +

    This is the Imposter Syndrome talking for the most part… ↩︎

    +
  4. +
  5. +

    Fun fact: I actively squealed when VCM was announced. She’s a fascinating person with extremely varied career (to name a few: author, broadcaster/presenter, professional player, pornographer, former stand up comedian, customised inhaler trendsetter…) ↩︎

    +
  6. +
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/archives/index.html b/public/archives/index.html new file mode 100644 index 0000000..a63f664 --- /dev/null +++ b/public/archives/index.html @@ -0,0 +1,116 @@ + + + + - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

+
Posted on May 28, 2019
+
+ + +
+ +

Table of Contents

+ + +
+ +
+ +
+ + + + +
+
+ +
+ + diff --git a/public/categories/beginner/index.html b/public/categories/beginner/index.html new file mode 100644 index 0000000..dacc602 --- /dev/null +++ b/public/categories/beginner/index.html @@ -0,0 +1,86 @@ + + + + Beginner - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "Beginner"

+ + + + +
+ + diff --git a/public/categories/beginner/index.xml b/public/categories/beginner/index.xml new file mode 100644 index 0000000..95ae84f --- /dev/null +++ b/public/categories/beginner/index.xml @@ -0,0 +1,20 @@ + + + + Beginner on The Median Duck + http://localhost:4321/themedianduck/categories/beginner/ + Recent content in Beginner on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/categories/fearlessness-how-to-stop-running-from-space/index.html b/public/categories/fearlessness-how-to-stop-running-from-space/index.html new file mode 100644 index 0000000..1f0e5fe --- /dev/null +++ b/public/categories/fearlessness-how-to-stop-running-from-space/index.html @@ -0,0 +1,141 @@ + + + + Fearlessness: How to Stop Running from Space - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Fearlessness: How to Stop Running from Space

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos.

+

We are afraid of empty space in our lives.

+

The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives.

+

We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. We try to fill every second with activity, with something useful, as if silence and space are not valuable.

+

But what are we afraid of?

+

And who would we be if we didn’t have that fear?

+

We’re afraid of space and stillness and silence because it highlights the uncertainty, instability, groundlessness, insecurity, shakiness that lie underneath every second of our lives. We’re afraid of having to face this instability and uncertainty, of having to feel the fear of it.

+

Without the fear of all of the uncertainty that is highlighted by space … we become free.

+

I know in my life, when I allow myself to have stillness, silence, solitude, simplicity and space … it leaves room to face whatever is coming up for me. It gives me room to fully feel any feelings that I’ve been avoiding. It allows me to be more honest with myself, instead of using distractions and busyness to cover up what I don’t want to see.

+

And in the end, I develop trust that the space is not something to be feared, but rather something to be treasured. A gift, filled with learning and not knowing and shakiness and beauty.

+

You might try allowing more space to be in your day, without filling it:

+
    +
  • Take some time between tasks for stillness.
  • +
  • Sit out in nature, in silence, without technology.
  • +
  • When you notice yourself reaching for your phone, pause. See if you can just be still, just savor some space.
  • +
  • When you feel uncertainty or instability in your life (hint: it’s always there), let yourself feel it. Be present with it, without needing to run or avoid.
  • +
  • When you feel fear, be open-hearted with it and allow yourself fully feel it, being friendly with it. Your relationship with fear will change if you become friendly with it.
  • +
  • Do less, and trust that things won’t fall apart. Or if they do fall apart, you can be present with that instability.
  • +
  • When you’re in line, driving, eating, walking, exercising … see if you can do those things in silence, without technology, without needing to do something “useful.” Find the value in these spaces.
  • +
  • Notice who you are without the fear of space.
  • +
+

Savor these spaces, their deliciousness. Savor the groundlessness, as something filled with freedom if we learn not to fear it. Be present with the fear and uncertainty, as good friends not as enemies.

+

Let your heart be open raw tender and vulnerable, and your mind embracing the spaciousness of the vast blue sky of open awareness.

+ +
+ + +
+
+ +
+ + diff --git a/public/categories/getting-started-with-traveling-ultralight/index.html b/public/categories/getting-started-with-traveling-ultralight/index.html new file mode 100644 index 0000000..6835ecc --- /dev/null +++ b/public/categories/getting-started-with-traveling-ultralight/index.html @@ -0,0 +1,116 @@ + + + + Getting Started with Traveling Ultralight - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Getting Started with Traveling Ultralight

+
Posted on 2020-03-18 DRAFT
+
+ + +
+

I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said.

+

I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. But then I remembered that I’m far from normal in this way.

+

I gave him a tip for getting started, and I recommend it for all of you, who want to travel light — or ultralight, as I call it, because for many people traveling light is taking a carry-on roller luggage. For me, having those roller bags is lugging too much, because you can run up stairs with it with ease, or carry it all over a city without worrying about stowing away your luggage somewhere first. It’s so much easier to travel ultralight.

+

Here’s the tip I gave him to get started: start by getting a small backpack (less than 20 liters) and then just travel with what fits in that.

+

That’s how to start. But you’ll probably want some guidance on what to put into the bag, and how to travel with so little. Here’s some guidance to get started:

+
    +
  • I travel with a lightweight laptop (Macbook Air), a few clothes, my phone, earbuds and some charging cords, toiletries, and almost nothing else. A lightweight windbreaker for wind and light rain (Patagonia Houdini). An eye mask and ear plugs. A collapsible water bottle. My passport. That’s about it. No extra shoes. No books. No suit. No travel pillow. No extra camera other than my phone. I’m not sure what else everyone else brings, but none of that.
  • +
  • I bring clothes that I can wash in the sink or shower and that will dry overnight. Lightweight stuff that I can layer. Often they’re workout-style clothes or things from companies like Outlier or Patagonia that travel well. I don’t bring enough underwear or socks for every day of the trip, because I wash them every couple of days. I only bring one or two extra T-shirts, generally wearing the same two shirts the whole trip, even if it’s a month long. No one has ever once cared what I wear when I’m traveling.
  • +
  • I bring minimal toiletries: a small shaver for my head, razor, toothbrush, floss small tubes of toothpaste and shaving cream, deodorant, nail clippers, ibuprofen.
  • +
  • For cold places, I have thermal underwear and a couple long-sleeve layers (generally all Patagonia capilene stuff), and a beanie. I don’t usually go to places where it’s snowing (I don’t know why, maybe snow isn’t my thing), so I don’t have clothes to deal with that weather.
  • +
  • For warm places, I will bring flip flops and swim trunks, and leave most of the colder layers behind.
  • +
+

That’s enough for a monthlong trip, which I’ve done multiple times with this kind of setup. For a shorter trip of a few days, I might bring even less.

+

I really love traveling this way, and am more than willing to sacrifice bringing extra things for the luxury of traveling lightweight.

+

By the way, you don’t need much more than this kind of setup even in everyday life.

+

For more info on this, check out my Ultralight ebook, and my friend Tynan has a great book called Forever Nomad.

+ +
+ + +
+
+ +
+ + diff --git a/public/categories/getting-started/index.html b/public/categories/getting-started/index.html new file mode 100644 index 0000000..a9e920b --- /dev/null +++ b/public/categories/getting-started/index.html @@ -0,0 +1,86 @@ + + + + Getting Started - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "Getting Started"

+ + + + +
+ + diff --git a/public/categories/getting-started/index.xml b/public/categories/getting-started/index.xml new file mode 100644 index 0000000..1ea69d7 --- /dev/null +++ b/public/categories/getting-started/index.xml @@ -0,0 +1,20 @@ + + + + Getting Started on The Median Duck + http://localhost:4321/themedianduck/categories/getting-started/ + Recent content in Getting Started on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/categories/hello-r-markdown/index.Rmd b/public/categories/hello-r-markdown/index.Rmd new file mode 100644 index 0000000..8768d78 --- /dev/null +++ b/public/categories/hello-r-markdown/index.Rmd @@ -0,0 +1,38 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(collapse = TRUE) +``` + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + +```{r cars} +summary(cars) +fit <- lm(dist ~ speed, data = cars) +fit +``` + +# Including Plots + +You can also embed plots. See Figure \@ref(fig:pie) for example: + +```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE} +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` diff --git a/public/categories/hello-r-markdown/index.html b/public/categories/hello-r-markdown/index.html new file mode 100644 index 0000000..0a804df --- /dev/null +++ b/public/categories/hello-r-markdown/index.html @@ -0,0 +1,151 @@ + + + + Hello R Markdown - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Hello R Markdown

+
Posted on 2020-12-01 DRAFT
+
+ + +
+

R Markdown

+

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

+

You can embed an R code chunk like this:

+
summary(cars)
+##      speed           dist       
+##  Min.   : 4.0   Min.   :  2.00  
+##  1st Qu.:12.0   1st Qu.: 26.00  
+##  Median :15.0   Median : 36.00  
+##  Mean   :15.4   Mean   : 42.98  
+##  3rd Qu.:19.0   3rd Qu.: 56.00  
+##  Max.   :25.0   Max.   :120.00
+fit <- lm(dist ~ speed, data = cars)
+fit
+## 
+## Call:
+## lm(formula = dist ~ speed, data = cars)
+## 
+## Coefficients:
+## (Intercept)        speed  
+##     -17.579        3.932
+

Including Plots

+

You can also embed plots. See Figure 1 for example:

+
par(mar = c(0, 1, 0, 1))
+pie(
+  c(280, 60, 20),
+  c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
+  col = c('#0292D8', '#F7EA39', '#C4B632'),
+  init.angle = -50, border = NA
+)
+
+ +
+ + +
+
+ +
+ + diff --git a/public/categories/hello-r-markdown/index_files/figure-html/pie-1.png b/public/categories/hello-r-markdown/index_files/figure-html/pie-1.png new file mode 100644 index 0000000..eef072f Binary files /dev/null and b/public/categories/hello-r-markdown/index_files/figure-html/pie-1.png differ diff --git a/public/categories/how-i-learned-to-stop-procrastinating-love-letting-go/index.html b/public/categories/how-i-learned-to-stop-procrastinating-love-letting-go/index.html new file mode 100644 index 0000000..ff912f7 --- /dev/null +++ b/public/categories/how-i-learned-to-stop-procrastinating-love-letting-go/index.html @@ -0,0 +1,127 @@ + + + + How I Learned to Stop Procrastinating, & Love Letting Go - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

How I Learned to Stop Procrastinating, & Love Letting Go

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

The end of procrastination is the art of letting go.

+

I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done.

+

Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. It stressed me out. My work was less-than-desirable when I did it last minute. Slowly, I started to realize that procrastination wasn’t doing me any favors. In fact, it was causing me a lot of grief.

+

But I couldn’t quit. I tried a lot of things. I tried time boxing and goal setting and accountability and the Pomodoro Technique and Getting Things Done. All are great methods, but they only last so long. Nothing really worked over the long term.

+

That’s because I wasn’t getting to the root problem.

+

I hadn’t figured out the skill that would save me from the procrastination.

+

Until I learned about letting go.

+

Letting go first came to me when I was quitting smoking. I had to let go of the “need” to smoke, the use of my crutch of cigarettes to deal with stress and problems.

+

Then I learned I needed to let go of other false needs that were causing me problems: sugar, junk food, meat, shopping, beer, possessions. I’m not saying I can never do these things again once I let go of these needs, but I let go of the idea that they’re really necessary. I let go of an unhealthy attachment to them.

+

Then I learned that distractions and the false need to check my email and news and other things online … were causing me problems. They were causing my procrastination.

+

So I learned to let go of those too.

+

Here’s the process I used to let go of the distractions and false needs that cause procrastination:

+

I paid attention to the pain they cause me, later, instead of only the temporary comfort/pleasure they gave me right away. +I thought about the person I want to be, the life I want to live. I set my intentions to do the good work I think I should do. +I watched my urges to check things, to go to the comfort of distractions. I saw that I wanted to escape discomfort of something hard, and go to the comfort of something familiar and easy. +I realized I didn’t need that comfort. I could be in discomfort and nothing bad would happen. In fact, the best things happen when I’m in discomfort. +And then I smile, and breathe, and let go.

+

And one step at a time, become the person I want to be.

+ +
+ + +
+
+ +
+ + diff --git a/public/categories/how-to-test-dark-mode/index.html b/public/categories/how-to-test-dark-mode/index.html new file mode 100644 index 0000000..c877a44 --- /dev/null +++ b/public/categories/how-to-test-dark-mode/index.html @@ -0,0 +1,112 @@ + + + + How to test dark mode? - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

How to test dark mode?

+
Posted on 2018-03-18 DRAFT
+
+ +
+ tl;dr: + Wubba lubba dub dub +
+ +
+

You can set dark mode as default by setting params.mode to dark in config.toml or set it to auto which will detect based on your OS and switch to dark mode. For more details refer documentation

+

Here is how you can switch based on your OS

+ + +
+ + +
+
+ +
+ + diff --git a/public/categories/hugo-shortcodes/index.html b/public/categories/hugo-shortcodes/index.html new file mode 100644 index 0000000..cb2128e --- /dev/null +++ b/public/categories/hugo-shortcodes/index.html @@ -0,0 +1,355 @@ + + + + Hugo shortcodes - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+ +
+ +
+ + diff --git a/public/categories/index.html b/public/categories/index.html new file mode 100644 index 0000000..ba8059d --- /dev/null +++ b/public/categories/index.html @@ -0,0 +1,113 @@ + + + + Categories - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +

All tags

+ + + + + + + + +
+ +
+ +
+ + diff --git a/public/categories/index.xml b/public/categories/index.xml new file mode 100644 index 0000000..9a804c5 --- /dev/null +++ b/public/categories/index.xml @@ -0,0 +1,34 @@ + + + + Categories on The Median Duck + //localhost:4321/categories/ + Recent content in Categories on The Median Duck + Hugo + en-us + © Christopher Nam + Sat, 06 Jul 2024 00:00:00 +0000 + + + Test + //localhost:4321/categories/test/ + Sat, 06 Jul 2024 00:00:00 +0000 + //localhost:4321/categories/test/ + + + + Trial + //localhost:4321/categories/trial/ + Sat, 06 Jul 2024 00:00:00 +0000 + //localhost:4321/categories/trial/ + + + + R + //localhost:4321/categories/r/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/categories/r/ + + + + diff --git a/public/categories/introduction/index.html b/public/categories/introduction/index.html new file mode 100644 index 0000000..403678b --- /dev/null +++ b/public/categories/introduction/index.html @@ -0,0 +1,86 @@ + + + + Introduction - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "Introduction"

+ + + + +
+ + diff --git a/public/categories/introduction/index.xml b/public/categories/introduction/index.xml new file mode 100644 index 0000000..8446175 --- /dev/null +++ b/public/categories/introduction/index.xml @@ -0,0 +1,20 @@ + + + + Introduction on The Median Duck + http://localhost:4321/themedianduck/categories/introduction/ + Recent content in Introduction on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/categories/new-post-on-archie/index.Rmarkdown b/public/categories/new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..e9196ed --- /dev/null +++ b/public/categories/new-post-on-archie/index.Rmarkdown @@ -0,0 +1,25 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? \ No newline at end of file diff --git a/public/categories/new-post-on-archie/index.html b/public/categories/new-post-on-archie/index.html new file mode 100644 index 0000000..a548871 --- /dev/null +++ b/public/categories/new-post-on-archie/index.html @@ -0,0 +1,126 @@ + + + + New Post on Archie - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

New Post on Archie

+
Posted on 2024-07-06
+
+ + +
+

Intro

+

This is my first post in the Archie template in hugo.

+

Here’s a random sample from the standard Normal distribution.

+
rnorm(5)
+
## [1] -0.3637057 -0.4214060  0.6501004 -0.8329920  1.3021409
+

Here’s an image of a duck.

+

+

Did I create a html from this?

+ +
+ + +
+
+ +
+ + diff --git a/public/categories/primer-when-you-have-too-much-to-do/index.html b/public/categories/primer-when-you-have-too-much-to-do/index.html new file mode 100644 index 0000000..464ff71 --- /dev/null +++ b/public/categories/primer-when-you-have-too-much-to-do/index.html @@ -0,0 +1,146 @@ + + + + Primer: When You Have Too Much to Do - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Primer: When You Have Too Much to Do

+
Posted on 2020-04-01 DRAFT
+
+ + +
+

You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more.

+

It all keeps piling up, and it can feel overwhelming.

+

How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate?

+

In this primer, I’ll look at some key strategies and tactics for taking on an overloaded life with an open heart, lots of energy, and a smile on your face.

+

The First Step: Triage

+

Whether you’re just starting your day, or you’re in the middle of the chaos and just need to find some sanity … the first step is to get into triage mode.

+

Triage, as you probably know, is sorting through the chaos to prioritize: what needs to be done now, what needs to be done today, what needs to be done this week, and what can wait? You’re looking at urgency, but also what’s meaningful and important.

+

Here’s what you might do:

+
    +
  • Pick out the things that need to be done today. Start a Short List for things you’re going to do today. That might be important tasks for big projects, urgent tasks that could result in damage if you don’t act, smaller admin tasks that you really should take care of today, and responding to important messages. I would recommend being ruthless and cutting out as much as you can, having just 5 things on your plate if that’s at all possible. Not everything needs to be done today, and not every email needs to be responded to.
  • +
  • Push some things to tomorrow and the rest of the week. If you have deadlines that can be pushed back (or renegotiated), do that. Spread the work out over the week, even into next week. What needs to be done tomorrow? What can wait a day or two longer?
  • +
  • Eliminate what you can. That might mean just not replying to some messages that aren’t that important and don’t really require a reply. It might mean telling some people that you can’t take on this project after all, or that you need to get out of the commitment that you said you’d do. Yes, this is uncomfortable. For now, just put them on a list called, “To Not Do,” and plan to figure out how to get out of them later.
  • +
+

OK, you have some breathing room and a manageable list now! Let’s shrink that down even further and just pick one thing.

+

Next: Focus on One Thing

+

With a lot on your plate, it’s hard to pick one thing to focus on. But that’s exactly what I’m going to ask you to do.

+

Pick one thing, and give it your focus. Yes, there are a lot of other things you can focus on. Yes, they’re stressing you out and making it hard to focus. But think about it this way: if you allow it all to be in your head all the time, that will always be your mode of being. You’ll always be thinking about everything, stressing out about it all, with a frazzled mind … unless you start shifting.

+

The shift:

+
    +
  • Pick something to focus on. Look at the triaged list from the first section … if you have 5-6 things on this Short List, you can assess whether there’s any super urgent, time-sensitive things you need to take care of. If there are, pick one of them. If not, pick the most important one — probably the one you have been putting off doing.
  • +
  • Clear everything else away. Just for a little bit. Close all browser tabs, turn off notifications, close open applications, put your phone away.
  • +
  • Put that one task before you, and allow yourself to be with it completely. Pour yourself into it. Think of it as a practice, of letting go (of everything else), of focus, of radical simplicity.
  • +
+

When you’re done (or after 15-20 minutes have gone by at least), you can switch to something else. But don’t allow yourself to switch until then.

+

By closing off all exits, by choosing one thing, by giving yourself completely to that thing … you’re now in a different mode that isn’t so stressful or spread thin. You’ve started a shift that will lead to focus and sanity.

+

Third: Schedule Time to Simplify

+

Remember the To Not Do list above? Schedule some time this week to start reducing your projects, saying no to people, getting out of commitments, crossing stuff off your task list … so that you can have some sanity back.

+

There are lots of little things that you’ve said “yes” to that you probably shouldn’t have. That’s why you’re overloaded. Protect your more important work, and your time off, and your peace of mind, by saying “no” to things that aren’t as important.

+

Schedule the time to simplify — you don’t have to do it today, but sometime soon — and you can then not have to worry about the things on your To Not Do list until then.

+

Fourth: Practice Mindful Focus

+

Go through the rest of the day with an attitude of “mindful focus.” That means that you are doing one thing at a time, being as present as you can, switching as little as you can.

+

Think of it as a settling of the mind. A new mode of being. A mindfulness practice (which means you won’t be perfect at it).

+

As you practice mindful focus, you’ll learn to practice doing things with an open heart, with curiosity and gratitude, and even joy. Try these one at a time as you get to do each task on your Short List.

+

You’ll find that you’re not so overloaded, but that each task is just perfect for that moment. And that’s a completely new relationship with the work that you do, and a new relationship with life.

+ +
+ + +
+
+ +
+ + diff --git a/public/categories/r/index.html b/public/categories/r/index.html new file mode 100644 index 0000000..e36540a --- /dev/null +++ b/public/categories/r/index.html @@ -0,0 +1,94 @@ + + + + R - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "R"

+ + + + +
+ + diff --git a/public/categories/r/index.xml b/public/categories/r/index.xml new file mode 100644 index 0000000..a21950b --- /dev/null +++ b/public/categories/r/index.xml @@ -0,0 +1,20 @@ + + + + R on The Median Duck + //localhost:4321/categories/r/ + Recent content in R on The Median Duck + Hugo + en-us + © Christopher Nam + Tue, 01 Dec 2020 21:13:14 -0500 + + + Hello R Markdown + //localhost:4321/2020/12/hello-r-markdown/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/2020/12/hello-r-markdown/ + R Markdown This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com. You can embed an R code chunk like this: summary(cars) ## speed dist ## Min. : 4.0 Min. : 2.00 ## 1st Qu.:12.0 1st Qu.: 26.00 ## Median :15.0 Median : 36.00 ## Mean :15.4 Mean : 42.98 ## 3rd Qu. + + + diff --git a/public/categories/setup/index.html b/public/categories/setup/index.html new file mode 100644 index 0000000..826435b --- /dev/null +++ b/public/categories/setup/index.html @@ -0,0 +1,86 @@ + + + + Setup - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "Setup"

+ + + + +
+ + diff --git a/public/categories/setup/index.xml b/public/categories/setup/index.xml new file mode 100644 index 0000000..c7ff6f8 --- /dev/null +++ b/public/categories/setup/index.xml @@ -0,0 +1,20 @@ + + + + Setup on The Median Duck + http://localhost:4321/themedianduck/categories/setup/ + Recent content in Setup on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/categories/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db b/public/categories/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/public/categories/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db differ diff --git a/public/categories/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/public/categories/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..c6e7b0d --- /dev/null +++ b/public/categories/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,180 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +sections: ["intro", "setup", "data"] +categories: ["Getting Started", "Introduction", "Beginner", "Setup"] +tags: + - Introduction + - Setup + - Beginner + - Getting Started +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 1 +--- + +```{r setup, include=FALSE, echo = FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../") +``` + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +# Introduction and Objective + +This article provides an overview of *Trabajo de las Mesas*, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC + +The article will also provide guidance on how to connect to the database from within . + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM^\[Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.\]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +## Data Quality + +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. . + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + +## Why This Datasource? + +As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + +However, for the purposes of this project, being able to query from database has several advantages. This includes: + +- Quality: Data being in a structured tabular format which often leads to better data quality +- Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc) +- Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + +## Potential Areas to Explore in the Future + +- Greater understanding of how the data is being collected. + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- Generate a data dictionary page + - What tables are available, samples of the data, what the table pertains to, and key columns. +- A dashboard on data quality. + - A highlevel overview of the quality and how recent the data is. + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download} +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +repo_root_dir <- getwd() +db_file_name <- "taskmaster.db" +data_dir <- "Data" + +db_data_location <- file.path(repo_root_dir, data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(repo_root_dir, data_dir))){ + dir.create(file.path(repo_root_dir, data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` + +## Connecting to the `.db` file + +Now that the database file has been successfully downloaded, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + +## Querying the Database + +Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation + +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts +LEFT JOIN people tp +ON ts.id = tp.series +AND ts.champion = tp.id +WHERE ts.special <> 1 +" + +results <- dbGetQuery(tm_db, query) +results +``` + +The results of this query already indicate interesting insights, namely that 204 days (approximately `r round(204/7)` weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag? + +# Times Up! + +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/public/categories/strength-in-data-connecting-to-the-taskmaster-database/index.html b/public/categories/strength-in-data-connecting-to-the-taskmaster-database/index.html new file mode 100644 index 0000000..7216625 --- /dev/null +++ b/public/categories/strength-in-data-connecting-to-the-taskmaster-database/index.html @@ -0,0 +1,305 @@ + + + + Strength in Data: Connecting to the Taskmaster Database - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Strength in Data: Connecting to the Taskmaster Database

+
Posted on 2024-07-10
+
+ + +
+

Your Task

+
+

Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now!

+
+

Introduction and Objective

+

This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC

+

The article will also provide guidance on how to connect to the database from within .

+

Trabajo de las Mesas Database

+

Trabajo de las Mesas (TdlM^[Taskmaster fanatics will know that this is in reference to the hint in S2E5’s task Build a bridge for the potato., which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant.

+

The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project.

+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource. .

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+

Why This Datasource?

+

As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+

Potential Areas to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
    +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
    +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
    +
  • +
+

Connecting to the Database from R

+

Downloading the .db file

+

It is possible to view and query these the numerous tables in TdlM from the website itself. However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as R or python, naturally leads to repeatablility and reproduceability.

+

I opting choosing to choose R for this project due to my familarity with it, and the high level visualisations and modelling that can be employed.

+

The tables displayed on the website are powered from the following database file which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist.

+
# URL where Database file resides. We will download from here.
+db_url <- "https://tdlm.fly.dev/taskmaster.db"
+
+# Where the data will be stored locally
+repo_root_dir <- getwd()
+db_file_name <- "taskmaster.db"
+data_dir <- "Data"
+
+db_data_location <- file.path(repo_root_dir, data_dir, db_file_name)
+
+
+# Create Data Directory if does not exist
+if(!file.exists(file.path(repo_root_dir, data_dir))){
+    dir.create(file.path(repo_root_dir, data_dir))
+}
+
+# Download file specified by URL, save in the local destination.
+if(!file.exists(db_data_location)){
+    download.file(url = db_url, destfile = db_data_location, mode = "wb")
+}
+

Connecting to the .db file

+

Now that the database file has been successfully downloaded, we can start to connect to it from R directory. The DBI package will be employed to establish this connection.

+
package_name <- "RSQLite"
+
+if(!require(package_name, character.only = TRUE)){
+    install.packages(package_name, character.only = TRUE)
+} else{
+    library(package_name, character.only = TRUE)    
+}
+
## Loading required package: RSQLite
+
# Driver used to establish database connection
+sqlite_driver <- dbDriver("SQLite")
+
+# Making the connection 
+tm_db <- dbConnect(sqlite_driver, dbname = db_data_location)
+

If successful, we should be able to list all the tables included in the database.

+
# List all tables that are available in the database
+dbListTables(tm_db)
+
##  [1] "attempts"           "discrepancies"      "episode_scores"    
+##  [4] "episodes"           "intros"             "measurements"      
+##  [7] "normalized_scores"  "objectives"         "people"            
+## [10] "podcast"            "profanity"          "series"            
+## [13] "series_scores"      "special_locations"  "task_briefs"       
+## [16] "task_readers"       "task_winners"       "tasks"             
+## [19] "tasks_by_objective" "team_tasks"         "teams"             
+## [22] "title_coiners"      "title_stats"
+

Querying the Database

+

Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from R to access the data. For example:

+

A Basic SELECT query

+
# A Basic Select query  on the series table.
+query <- "SELECT * FROM series LIMIT 10"
+
+dbGetQuery(tm_db, query)
+
##    id     name episodes champion  air_start    air_end studio_start studio_end
+## 1  -7  CoC III        0       NA 2024-??-?? 2024-??-??   2023-11-28 2023-11-28
+## 2  -6 NYT 2024        0       NA 2024-01-01 2024-01-01   2023-11-27 2023-11-27
+## 3  -5 NYT 2023        1       96 2023-01-01 2023-01-01   2022-11-22 2022-11-22
+## 4  -4   CoC II        1       87 2022-06-23 2022-06-23   2021-09-15 2021-09-15
+## 5  -3 NYT 2022        1       73 2022-01-01 2022-01-01         <NA>       <NA>
+## 6  -2 NYT 2021        1       62 2021-01-01 2021-01-01         <NA>       <NA>
+## 7  -1      CoC        2       29 2017-12-13 2017-12-20   2017-11-20 2017-11-20
+## 8   1 Series 1        6        4 2015-07-28 2015-09-01   2015-03-23 2015-03-25
+## 9   2 Series 2        5       11 2016-06-21 2016-07-19         <NA>       <NA>
+## 10  3 Series 3        5       16 2016-10-04 2016-11-01         <NA>       <NA>
+##    points tasks special TMI
+## 1      NA    NA       1  88
+## 2      NA    NA       1  87
+## 3      76     5       1  66
+## 4      66     5       1  46
+## 5      68     5       1  47
+## 6      62     5       1  12
+## 7     164    10       1   6
+## 8     436    32       0   1
+## 9     417    28       0   2
+## 10    386    27       0   3
+

Advanced query

+

A more involved query involving JOIN and date manipulation

+
# A join, and data manipulation
+query <- "SELECT ts.name,
+ts.special as special_flag,
+tp.name as champion_name,
+tp.seat as chamption_seat,
+DATE(ts.studio_end) as studio_end, 
+DATE(ts.air_start) as air_start, 
+JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days
+FROM series ts
+LEFT JOIN people tp
+ON ts.id = tp.series
+AND ts.champion = tp.id
+WHERE ts.special <> 1
+"
+
+results <- dbGetQuery(tm_db, query)
+results
+
##         name special_flag    champion_name chamption_seat studio_end  air_start
+## 1   Series 1            0  Josh Widdicombe              2 2015-03-25 2015-07-28
+## 2   Series 2            0   Katherine Ryan              4       <NA> 2016-06-21
+## 3   Series 3            0      Rob Beckett              4       <NA> 2016-10-04
+## 4   Series 4            0    Noel Fielding              5       <NA> 2017-04-25
+## 5   Series 5            0     Bob Mortimer              2 2017-07-06 2017-09-13
+## 6   Series 6            0     Liza Tarbuck              3 2018-03-28 2018-05-02
+## 7   Series 7            0   Kerry Godliman              3 2018-07-25 2018-09-05
+## 8   Series 8            0      Lou Sanders              3 2019-03-27 2019-05-08
+## 9   Series 9            0        Ed Gamble              2 2019-07-24 2019-09-04
+## 10 Series 10            0  Richard Herring              5 2020-07-29 2020-10-15
+## 11 Series 11            0    Sarah Kendall              5       <NA> 2021-03-18
+## 12 Series 12            0 Morgana Robinson              4       <NA> 2021-09-23
+## 13 Series 13            0     Sophie Duker              5 2021-09-22 2022-04-14
+## 14 Series 14            0    Dara Ó Briain              1 2022-05-05 2022-09-29
+## 15 Series 15            0       Mae Martin              5 2022-09-28 2023-03-30
+## 16 Series 16            0     Sam Campbell              3 2023-05-12 2023-09-21
+##    broadcast_lag_days
+## 1                 125
+## 2                  NA
+## 3                  NA
+## 4                  NA
+## 5                  69
+## 6                  35
+## 7                  42
+## 8                  42
+## 9                  42
+## 10                 78
+## 11                 NA
+## 12                 NA
+## 13                204
+## 14                147
+## 15                183
+## 16                132
+

The results of this query already indicate interesting insights, namely that 204 days (approximately 29 weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag?

+

Times Up!

+

And that concludes this task! Hopefully you’ve been able to connect to the TdlM database directly through R and potentially inspired to start performing your own analysis.

+ +
+ + +
+
+ +
+ + diff --git a/public/categories/telegram-bot-for-github-actions/index.html b/public/categories/telegram-bot-for-github-actions/index.html new file mode 100644 index 0000000..765e029 --- /dev/null +++ b/public/categories/telegram-bot-for-github-actions/index.html @@ -0,0 +1,439 @@ + + + + Telegram Bot for GitHub Actions - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Telegram Bot for GitHub Actions

+
Posted on 2020-04-01 DRAFT
+
+ +
+ tl;dr: + Making GitHub Actions with Js Code +
+ +
+

Telegram

+

Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API.

+

GitHub Actions

+

GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. You can build, test and deploy your code with GitHub Actions. All these actions are called workflows and workflows differ in the job they’re doing. These maybe test workflows, build ones or deployment ones. You can find all the actions on GitHub in the marketplace

+

Building the Bot

+

Prerequisites

+
    +
  • Basic JavaScript Knowledge
  • +
  • Basic GitHub Knowledge
  • +
  • Telegram Account
  • +
+
+

There are templates for building actions. Here we’re gonna start from scratch

+
+

Environment Setup

+
    +
  • Node, You can download node from their website
  • +
  • NPM comes with node, so you don’t have to worry about it.
  • +
  • Initialize the Project
  • +
+
$ git init ## initialize a new git repository for version management
+---
+$ npm init
+
    +
  • dotenv, Dotenv can be downloaded via
  • +
+
$ npm i dotenv
+---
+$ yarn add dotenv
+
    +
  • node-telegram-bot-api, node-telegram-bot-api is a simple wrapper for building telegram bots. You can download it via
  • +
+
$ npm i node-telegram-bot-api
+---
+$ yarn add node-telegram-bot-api
+
    +
  • @zeit/ncc, NCC is a Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, GCC-style. It’s a dev dependency and can be downloaded
  • +
+
yarn add --dev @zeit/ncc
+---
+npm i -D @zeit/ncc
+

Folder Structure

+

The dist folder will be automatically created. action.yml will be made

+
.
+├── dist
+│   └── index.js
+├── index.js
+├── action.yml
+├── README.md
+└── package.json
+
    +
  • index.js is the file we’re defining the bot
  • +
  • action.yml is the file we’ll define the action and it’s behaviours
  • +
+

Making the Bot

+

We need to get an API bot token from telegram. For that Go to Telegram and Search for Botfather. It’s a bot. + +Create a new bot with the /newbot command and get the API key. We’ll need that, also talk to jsondump bot and get your chat id. The output may be like this, so

+
{
+  "update_id": 143943779,
+  "message": {
+    "message_id": 181575,
+    "from": {
+      "id": 123456 // this is what we need
+      "is_bot": false,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "language_code": "en"
+    },
+    "chat": {
+      "id": 123456,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "type": "private"
+    },
+    "date": 1584119424,
+    "text": "message"
+  }
+}
+

This will be needed for further use and We need to add it to the repo secrets which can be found in the repo settings. Be careful to add it as token and chat like as shown below +

+

Writing the Action and Building the Bot

+

Fire up the terminal/cmd and make a new folder. Install the dependencies. Run the following command

+
$ touch index.js action.yml
+

Open your favourite text editor within the folder or with the file. We’ll define the bot in index.js

+
require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+const {
+    INPUT_STATUS: ipstatus,
+    INPUT_TOKEN: tgtoken,//Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor,// Issue made by
+    INPUT_IU_BODY: ibody,// Issue Body
+    INPUT_PR_NUM: pnum,// PR Number
+    INPUT_PR_STATE: prstate,// PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle,// PR Title
+    INPUT_PR_BODY: pbody,// Body of the PR
+    GITHUB_EVENT_NAME: ghevent,// Name of the trigger event
+    GITHUB_REPOSITORY: repo,// Repository the trigger was made from
+    GITHUB_ACTOR: ghactor,// User who triggered the action
+    GITHUB_SHA: sha,// Commit ID
+    GITHUB_WORKFLOW: ghwrkflw// Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+

First, we’re defining the dotenv for config and initializing Telegram Bot. Here we’re defining the alias variables for the environment variables. You might notice an INPUT_ for almost every environment variable, this is because GitHub Actions pass the env variable with an INPUT prefix. Other env variables are action’s default environment variables. Then we initialized the bot with the API token.

+

GitHub actions could be triggered with Issues, Pull Request or Pushes. You can find the trigger events here. Here we’re gonna get a message from the bot when an Issue or Pull Request or a Push event has happened.

+
const evresp = (gevent) => {
+    switch (gevent) {
+
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+

In these lines of code, we’re just initializing a switch statement for the responses. We’re also declaring an anonymous function to use the switch responses via a function later. We’re using all the defined variables in the switch. You can check the trigger Events to get how the event is triggered and what keyword should be used.

+

Now for the last part of the Js file, we just take the response from the switch and assign it to a constant. Then we use the sendMessage function of the node-telegram-bot-api to send the message to the bot with the chatid and the output as the arguments.

+
const output = evresp(ghevent)
+

bot.sendMessage(chatid,output,{parse_mode : “Markdown”})

+

Compiling and Minifying the Js code

+

Since we have installed @zeit/ncc and this is used for the making the whole program with all the APIs to a single file and we need to use NCC for that. We just need to run

+
yarn run ncc build index.js -C -m -o dist
+

or you might wanna add the following to you package.json file, and run npm run test to compile and minify the code.

+
"scripts": {
+    "test": "ncc build index.js -C -m -o dist"
+  },
+

This will create a dist folder with and index.js file which contains the compiled code.

+

Making it a valid action

+

For making this Js file a valid action, we need to add an action.yml file. The action.yml for this action is like this

+
name: 'Action Name'
+description: 'Action Descreption'
+author: '<author name>'
+inputs: 
+  chat:
+    description: 'Chat to send: chat id or @channel_name'
+    required: true
+  token:
+    description: 'Telegram Bot token'
+    required: true
+  status:
+    description: 'Job status'
+    required: true
+  iu_title: 
+    description: 'Issue Title'
+    default: ${{ github.event.issue.title }}
+  iu_num:
+    description: 'Issue Number'
+    default: ${{ github.event.issue.number }}
+  iu_actor: 
+    description: 'Issue Triggerer'
+    default: ${{ github.event.issue.user.login }}
+  iu_com:
+    description: 'Issue Comment'
+    default: ${{github.event.comment.body}}
+  pr_state:
+    description: 'State of the PR'
+    default: ${{ github.event.action }}
+  pr_num:
+    description: 'PR Number'
+    default: ${{ github.event.number }}
+  pr_title:
+    description: 'Title of the PR'
+    default: ${{ github.event.pull_request.title }}
+  pr_body:
+    description: 'Body/Contents of the PR'
+    default: ${{ github.event.pull_request.body }}
+runs:
+  using: "node12"
+  main: "dist/index.js"
+branding:
+  icon: 'repeat'  
+  color: 'green'
+

Here we’re defining the Input variables to be loaded for the action in GitHub’s runtime environemt. All these default data are taken from the response of the webhooks which are send by GitHub when a trigger event is occured. You can find out more in the Action Documentation Here.

+
runs:
+  using: "node12"
+  main: "dist/index.js"
+

Here we are defining that this is a node action and should run in an environment with node, and the file which should be run, here the index.js file in the dist folder. That should do it. Create a new commit and push it to a repo. Create a new tag and this action will appear in the marketplace.

+

Defining a workflow to test your action

+

GitHub Action workflows are defined using the .yml syntax. Here is an example of a sample workflow for this action

+
name: <Workflow Name>
+
+on:
+  push:
+  pull_request:
+    types: [opened, closed]
+  issues:
+    types: [opened, closed, reopened]
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: <AnyName>
+        uses: <username>/<repo>@master
+        if: always()
+        with:
+          chat: ${{ secrets.chat }}
+          token: ${{ secrets.token }}
+          status: ${{ job.status }}
+

The Complete code for the bot is

+
//Initializing dotenv and the bot
+require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+// aliasing the environment variables 
+const {
+    INPUT_STATUS: ipstatus, 
+    INPUT_TOKEN: tgtoken, //Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor, // Issue made by
+    INPUT_IU_BODY: ibody, // Issue Body
+    INPUT_PR_NUM: pnum, // PR Number
+    INPUT_PR_STATE: prstate, // PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle, // PR Title
+    INPUT_PR_BODY: pbody, // Body of the PR
+    GITHUB_EVENT_NAME: ghevent, // Name of the trigger event
+    GITHUB_REPOSITORY: repo, // Repository the trigger was made from
+    GITHUB_ACTOR: ghactor, // User who triggered the action
+    GITHUB_SHA: sha, // Commit ID
+    GITHUB_WORKFLOW: ghwrkflw // Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+// Function to return the response for the specific trigger
+const evresp = (gevent) => {
+    switch (gevent) {
+//Switch statement for issues
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+// Switch statement for Pull Requests
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+// switch statement for Pushes
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+// assigning the output to a variable
+const output = evresp(ghevent)
+// sending the message
+bot.sendMessage(chatid,output,{parse_mode : "Markdown"})
+

+

You can try out many different items using actions and this is just a sample action to get you started. Maybe sending Cat GIFs if the build succeded on the pull request or sending a welcome message to a first time contributor. You imagination is the limit😄 and Never Stop being ⚡️

+ +
+ + +
+
+ +
+ + diff --git a/public/categories/test/index.html b/public/categories/test/index.html new file mode 100644 index 0000000..13870eb --- /dev/null +++ b/public/categories/test/index.html @@ -0,0 +1,94 @@ + + + + Test - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "test"

+ + + + +
+ + diff --git a/public/categories/test/index.xml b/public/categories/test/index.xml new file mode 100644 index 0000000..7cab19f --- /dev/null +++ b/public/categories/test/index.xml @@ -0,0 +1,20 @@ + + + + Test on The Median Duck + //localhost:4321/categories/test/ + Recent content in Test on The Median Duck + Hugo + en-us + © Christopher Nam + Sat, 06 Jul 2024 00:00:00 +0000 + + + New Post on Archie + //localhost:4321/2024/07/new-post-on-archie/ + Sat, 06 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/new-post-on-archie/ + Intro This is my first post in the Archie template in hugo. Here&rsquo;s a random sample from the standard Normal distribution. rnorm(5) ## [1] -0.3637057 -0.4214060 0.6501004 -0.8329920 1.3021409 Here&rsquo;s an image of a duck. Did I create a html from this? + + + diff --git a/public/categories/trial/index.html b/public/categories/trial/index.html new file mode 100644 index 0000000..2f378c5 --- /dev/null +++ b/public/categories/trial/index.html @@ -0,0 +1,94 @@ + + + + Trial - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "trial"

+ + + + +
+ + diff --git a/public/categories/trial/index.xml b/public/categories/trial/index.xml new file mode 100644 index 0000000..de5b05c --- /dev/null +++ b/public/categories/trial/index.xml @@ -0,0 +1,20 @@ + + + + Trial on The Median Duck + //localhost:4321/categories/trial/ + Recent content in Trial on The Median Duck + Hugo + en-us + © Christopher Nam + Sat, 06 Jul 2024 00:00:00 +0000 + + + New Post on Archie + //localhost:4321/2024/07/new-post-on-archie/ + Sat, 06 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/new-post-on-archie/ + Intro This is my first post in the Archie template in hugo. Here&rsquo;s a random sample from the standard Normal distribution. rnorm(5) ## [1] -0.3637057 -0.4214060 0.6501004 -0.8329920 1.3021409 Here&rsquo;s an image of a duck. Did I create a html from this? + + + diff --git a/public/categories/typography/index.html b/public/categories/typography/index.html new file mode 100644 index 0000000..d1307e3 --- /dev/null +++ b/public/categories/typography/index.html @@ -0,0 +1,155 @@ + + + + Typography - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Typography

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 1

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 2

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 3

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 4

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 5
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 6
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Typography

+

Lid est laborum et dolorum fuga, This is an example inline link. Et harum quidem rerum facilis, This is bold and emphasis cumque nihilse impedit quo minus id quod amets untra dolor amet sad. While this is code block() and following is a pre tag

+
print 'this is pre tag'
+
+

Following is the syntax highlighted code block

+
func getCookie(name string, r interface{}) (*http.Cookie, error) {
+	rd := r.(*http.Request)
+	cookie, err := rd.Cookie(name)
+	if err != nil {
+		return nil, err
+	}
+	return cookie, nil
+}
+
+func setCookie(cookie *http.Cookie, w interface{}) error {
+	// Get write interface registered using `Acquire` method in handlers.
+	wr := w.(http.ResponseWriter)
+	http.SetCookie(wr, cookie)
+	return nil
+}
+

This is blockquote, Will make it better now

+
+

‘I want to do with you what spring does with the cherry trees.’ cited ~Pablo Neruda*

+
+
+

Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit

+
+

Unordered list

+
    +
  • Red
  • +
  • Green
  • +
  • Blue
  • +
+

Ordered list

+
    +
  1. Red
  2. +
  3. Green
  4. +
  5. Blue
  6. +
+ +
+ + +
+
+ +
+ + diff --git a/public/contact/index.html b/public/contact/index.html new file mode 100644 index 0000000..a6eee06 --- /dev/null +++ b/public/contact/index.html @@ -0,0 +1,10 @@ + + + + http://localhost:4321/themedianduck/about/ + + + + + + diff --git a/public/css/dark.023e8291221604ece4297cd12e8603e96659c53ee97a1298db6fc5bcf917c768.css b/public/css/dark.023e8291221604ece4297cd12e8603e96659c53ee97a1298db6fc5bcf917c768.css new file mode 100644 index 0000000..1c08fb3 --- /dev/null +++ b/public/css/dark.023e8291221604ece4297cd12e8603e96659c53ee97a1298db6fc5bcf917c768.css @@ -0,0 +1,176 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: "monospace"; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.0bb93a6c363f3abed62b5c5c0dc31d5c7eeb9adddbd85f577db22e8407abe702.css b/public/css/dark.0bb93a6c363f3abed62b5c5c0dc31d5c7eeb9adddbd85f577db22e8407abe702.css new file mode 100644 index 0000000..9c8fa3f --- /dev/null +++ b/public/css/dark.0bb93a6c363f3abed62b5c5c0dc31d5c7eeb9adddbd85f577db22e8407abe702.css @@ -0,0 +1,176 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: "Lucida Console"; + font-size: 16px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.0d2b0f55d455a2af2ba0367ae94eb6dbea351492fd95b5b7f419963aedebd8cf.css b/public/css/dark.0d2b0f55d455a2af2ba0367ae94eb6dbea351492fd95b5b7f419963aedebd8cf.css new file mode 100644 index 0000000..d756a5d --- /dev/null +++ b/public/css/dark.0d2b0f55d455a2af2ba0367ae94eb6dbea351492fd95b5b7f419963aedebd8cf.css @@ -0,0 +1,168 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.0eb53a56f7054b57369c036a966a647aac9219c5730bc12aad364dc4dc0d1ed8.css b/public/css/dark.0eb53a56f7054b57369c036a966a647aac9219c5730bc12aad364dc4dc0d1ed8.css new file mode 100644 index 0000000..6e57132 --- /dev/null +++ b/public/css/dark.0eb53a56f7054b57369c036a966a647aac9219c5730bc12aad364dc4dc0d1ed8.css @@ -0,0 +1,171 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + font-family: "Roboto Mono"; + min-height: 40px; + padding-left: 48px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.1137fcddd181d46cbae9da8c42b78131e2de438f3381fe2ac5843a2e05057b5d.css b/public/css/dark.1137fcddd181d46cbae9da8c42b78131e2de438f3381fe2ac5843a2e05057b5d.css new file mode 100644 index 0000000..9a71905 --- /dev/null +++ b/public/css/dark.1137fcddd181d46cbae9da8c42b78131e2de438f3381fe2ac5843a2e05057b5d.css @@ -0,0 +1,181 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +blockquote { + border-color: red; + background-color: #FCF5E5; + color: black; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + border-color: red; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.1ab3462a0dbc0155cbc12e47a4375cb6554d12f227295cf6ffa5298e25bd182c.css b/public/css/dark.1ab3462a0dbc0155cbc12e47a4375cb6554d12f227295cf6ffa5298e25bd182c.css new file mode 100644 index 0000000..61ff016 --- /dev/null +++ b/public/css/dark.1ab3462a0dbc0155cbc12e47a4375cb6554d12f227295cf6ffa5298e25bd182c.css @@ -0,0 +1,170 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + text-decoration: bold; + font-family: "Roboto Mono"; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.1f7e187b21239bf147641e4514741fa7babb895030e15e0d016817d54362e666.css b/public/css/dark.1f7e187b21239bf147641e4514741fa7babb895030e15e0d016817d54362e666.css new file mode 100644 index 0000000..ffc9fea --- /dev/null +++ b/public/css/dark.1f7e187b21239bf147641e4514741fa7babb895030e15e0d016817d54362e666.css @@ -0,0 +1,176 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: "Courier New"; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.218bb29defab25daff516abfee4f0e4a1592746ae10c4c8b628db94e50871581.css b/public/css/dark.218bb29defab25daff516abfee4f0e4a1592746ae10c4c8b628db94e50871581.css new file mode 100644 index 0000000..866eb63 --- /dev/null +++ b/public/css/dark.218bb29defab25daff516abfee4f0e4a1592746ae10c4c8b628db94e50871581.css @@ -0,0 +1,179 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + background-color: darkblue; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.2603bfe81d8c88af3819bbcb535777ee3ad937dd7aa96d7fe6d702543d6f21e5.css b/public/css/dark.2603bfe81d8c88af3819bbcb535777ee3ad937dd7aa96d7fe6d702543d6f21e5.css new file mode 100644 index 0000000..9529fd9 --- /dev/null +++ b/public/css/dark.2603bfe81d8c88af3819bbcb535777ee3ad937dd7aa96d7fe6d702543d6f21e5.css @@ -0,0 +1,171 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + font-family: "Roboto Mono"; + min-height: 40px; + align-content:"center"; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.27fe6be75f745ed7f1d9d2a42ae66ceed3807706885dd0dcdbf5805a02ea4872.css b/public/css/dark.27fe6be75f745ed7f1d9d2a42ae66ceed3807706885dd0dcdbf5805a02ea4872.css new file mode 100644 index 0000000..7094fc9 --- /dev/null +++ b/public/css/dark.27fe6be75f745ed7f1d9d2a42ae66ceed3807706885dd0dcdbf5805a02ea4872.css @@ -0,0 +1,171 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + font-family: "Roboto Mono"; + min-height: 60px; + align-content:"center"; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.2a01d476efc1a364d9221a24c49d45d7a1c93a4294eeaaf20d3bd61bfcb49cae.css b/public/css/dark.2a01d476efc1a364d9221a24c49d45d7a1c93a4294eeaaf20d3bd61bfcb49cae.css new file mode 100644 index 0000000..8da6041 --- /dev/null +++ b/public/css/dark.2a01d476efc1a364d9221a24c49d45d7a1c93a4294eeaaf20d3bd61bfcb49cae.css @@ -0,0 +1,172 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.2cb72c9b9e46c394abac45a5febbafc0c498d827b5a3cf8713310cbd3d5c781a.css b/public/css/dark.2cb72c9b9e46c394abac45a5febbafc0c498d827b5a3cf8713310cbd3d5c781a.css new file mode 100644 index 0000000..673cdf4 --- /dev/null +++ b/public/css/dark.2cb72c9b9e46c394abac45a5febbafc0c498d827b5a3cf8713310cbd3d5c781a.css @@ -0,0 +1,174 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: "Lucida Console"; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.30a41b26f461083e38fade2f4d3fb58d417c953811d787ecb4070360c9b159a6.css b/public/css/dark.30a41b26f461083e38fade2f4d3fb58d417c953811d787ecb4070360c9b159a6.css new file mode 100644 index 0000000..8ea5ab8 --- /dev/null +++ b/public/css/dark.30a41b26f461083e38fade2f4d3fb58d417c953811d787ecb4070360c9b159a6.css @@ -0,0 +1,170 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.32fe667475ebdd4a1c301ef566032b3df09ad2006d0ad92cd2437fbab02d96d8.css b/public/css/dark.32fe667475ebdd4a1c301ef566032b3df09ad2006d0ad92cd2437fbab02d96d8.css new file mode 100644 index 0000000..5fc3f78 --- /dev/null +++ b/public/css/dark.32fe667475ebdd4a1c301ef566032b3df09ad2006d0ad92cd2437fbab02d96d8.css @@ -0,0 +1,169 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + font-family: "Roboto Mono"; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.361ec600f7e79a10ce6db4791a493a602a99d0c84cb26d3c64ad0232ca8aceb4.css b/public/css/dark.361ec600f7e79a10ce6db4791a493a602a99d0c84cb26d3c64ad0232ca8aceb4.css new file mode 100644 index 0000000..b45696c --- /dev/null +++ b/public/css/dark.361ec600f7e79a10ce6db4791a493a602a99d0c84cb26d3c64ad0232ca8aceb4.css @@ -0,0 +1,179 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + border-color: red; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.3b46b948e9127f345e463f0405a878064b79ef42e1820b15ea95ad4abffbe0f9.css b/public/css/dark.3b46b948e9127f345e463f0405a878064b79ef42e1820b15ea95ad4abffbe0f9.css new file mode 100644 index 0000000..2ec3cb0 --- /dev/null +++ b/public/css/dark.3b46b948e9127f345e463f0405a878064b79ef42e1820b15ea95ad4abffbe0f9.css @@ -0,0 +1,181 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +blockquote { + border-color: red; + background-color: #FCF5E5; + color: black; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-family: 'Roboto Mono', monospace; + font-size: 18px; + font-weight: 400; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + border-color: red; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.3d4e84970aad49c6bb5f5a88e4ad85a36308f4ecc2dd0318e94ca36c305666bd.css b/public/css/dark.3d4e84970aad49c6bb5f5a88e4ad85a36308f4ecc2dd0318e94ca36c305666bd.css new file mode 100644 index 0000000..463a721 --- /dev/null +++ b/public/css/dark.3d4e84970aad49c6bb5f5a88e4ad85a36308f4ecc2dd0318e94ca36c305666bd.css @@ -0,0 +1,181 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +blockquote { + border-color: red; + background-color: #FCF5E5; + color: black; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-family: 'Fira Sans', sans-serif; + font-size: 18px; + font-weight: 400; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + border-color: red; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.3e937a33d6350d260fc953cc3546eb4d3647cf7143c8ce8091a52b4cf39b9f63.css b/public/css/dark.3e937a33d6350d260fc953cc3546eb4d3647cf7143c8ce8091a52b4cf39b9f63.css new file mode 100644 index 0000000..a708b3e --- /dev/null +++ b/public/css/dark.3e937a33d6350d260fc953cc3546eb4d3647cf7143c8ce8091a52b4cf39b9f63.css @@ -0,0 +1,169 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + text-decoration: bold; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.3eee435dd772efa82603fe0a4d488f712acc22206cd25f814192d36941705af4.css b/public/css/dark.3eee435dd772efa82603fe0a4d488f712acc22206cd25f814192d36941705af4.css new file mode 100644 index 0000000..96bcf9f --- /dev/null +++ b/public/css/dark.3eee435dd772efa82603fe0a4d488f712acc22206cd25f814192d36941705af4.css @@ -0,0 +1,170 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + font-family: "Roboto Mono"; + min-height: 30px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.4d6a54a8d249b01d04af193fd88c0a0009c4a8b875d7daa9d5ada375a863afcc.css b/public/css/dark.4d6a54a8d249b01d04af193fd88c0a0009c4a8b875d7daa9d5ada375a863afcc.css new file mode 100644 index 0000000..14665f6 --- /dev/null +++ b/public/css/dark.4d6a54a8d249b01d04af193fd88c0a0009c4a8b875d7daa9d5ada375a863afcc.css @@ -0,0 +1,170 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + text-decoration: bold; + font-family: Consolas; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.515e2d5eba404554a5cd83e8ef6342a4fc34bfb3e07638aeb2e59668e485bceb.css b/public/css/dark.515e2d5eba404554a5cd83e8ef6342a4fc34bfb3e07638aeb2e59668e485bceb.css new file mode 100644 index 0000000..211f6f3 --- /dev/null +++ b/public/css/dark.515e2d5eba404554a5cd83e8ef6342a4fc34bfb3e07638aeb2e59668e485bceb.css @@ -0,0 +1,170 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + text-decoration: bold; + font-family: "Segoe Print", "Times New Roman"; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.51da05867e950f9a285cdb879d7514abbfafa50ad80b365086f507be2040bac7.css b/public/css/dark.51da05867e950f9a285cdb879d7514abbfafa50ad80b365086f507be2040bac7.css new file mode 100644 index 0000000..8e5f734 --- /dev/null +++ b/public/css/dark.51da05867e950f9a285cdb879d7514abbfafa50ad80b365086f507be2040bac7.css @@ -0,0 +1,176 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: Courier; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.53ca5c131680137084bf0a534d892573cf9b227d95f07a6065e598f4c80345b2.css b/public/css/dark.53ca5c131680137084bf0a534d892573cf9b227d95f07a6065e598f4c80345b2.css new file mode 100644 index 0000000..8ef5062 --- /dev/null +++ b/public/css/dark.53ca5c131680137084bf0a534d892573cf9b227d95f07a6065e598f4c80345b2.css @@ -0,0 +1,175 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.53edd6a3d2f69918210c703b9dc7c23ab638ec7832e7225360d42732c68600f9.css b/public/css/dark.53edd6a3d2f69918210c703b9dc7c23ab638ec7832e7225360d42732c68600f9.css new file mode 100644 index 0000000..3a4cec2 --- /dev/null +++ b/public/css/dark.53edd6a3d2f69918210c703b9dc7c23ab638ec7832e7225360d42732c68600f9.css @@ -0,0 +1,160 @@ +body { + color: white; + background-color: #202124; + contain-intrinsic-width: 100%; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.583222a694aa7f8da0c059893b59801be1c23f942ccb5b262abdfcdbd6a3c26e.css b/public/css/dark.583222a694aa7f8da0c059893b59801be1c23f942ccb5b262abdfcdbd6a3c26e.css new file mode 100644 index 0000000..f182765 --- /dev/null +++ b/public/css/dark.583222a694aa7f8da0c059893b59801be1c23f942ccb5b262abdfcdbd6a3c26e.css @@ -0,0 +1,174 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: italic; + font-family: "Lucida Sans Typewriter", "Lucida Console", monaco, "Bitstream Vera Sans Mono", monospace; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.5863c8af913813ad5e90b9df89fe1d508479220453545cb006625df0a9f514d0.css b/public/css/dark.5863c8af913813ad5e90b9df89fe1d508479220453545cb006625df0a9f514d0.css new file mode 100644 index 0000000..ce8a672 --- /dev/null +++ b/public/css/dark.5863c8af913813ad5e90b9df89fe1d508479220453545cb006625df0a9f514d0.css @@ -0,0 +1,174 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: "Lucida Sans Typewriter", "Lucida Console", monaco, "Bitstream Vera Sans Mono", monospace; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.64157d8a2bdccff7fa85c808b9ba17ac8a3723b59371e9d7c2b70d6e8ddca5dd.css b/public/css/dark.64157d8a2bdccff7fa85c808b9ba17ac8a3723b59371e9d7c2b70d6e8ddca5dd.css new file mode 100644 index 0000000..674131b --- /dev/null +++ b/public/css/dark.64157d8a2bdccff7fa85c808b9ba17ac8a3723b59371e9d7c2b70d6e8ddca5dd.css @@ -0,0 +1,179 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + border-color: red; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.672523d53dac0d8ad45c538ef277063210db2e6302dfe48e8cad0615d46e83c3.css b/public/css/dark.672523d53dac0d8ad45c538ef277063210db2e6302dfe48e8cad0615d46e83c3.css new file mode 100644 index 0000000..c73befc --- /dev/null +++ b/public/css/dark.672523d53dac0d8ad45c538ef277063210db2e6302dfe48e8cad0615d46e83c3.css @@ -0,0 +1,167 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.6d2d7906ec82e192dea1125464695cb4f9376b447af298ff2da9720a90524447.css b/public/css/dark.6d2d7906ec82e192dea1125464695cb4f9376b447af298ff2da9720a90524447.css new file mode 100644 index 0000000..596a7de --- /dev/null +++ b/public/css/dark.6d2d7906ec82e192dea1125464695cb4f9376b447af298ff2da9720a90524447.css @@ -0,0 +1,171 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css b/public/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css new file mode 100644 index 0000000..f93adf1 --- /dev/null +++ b/public/css/dark.726cd11ca6eb7c4f7d48eb420354f814e5c1b94281aaf8fd0511c1319f7f78a4.css @@ -0,0 +1,159 @@ +body { + color: white; + background-color: #202124; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} \ No newline at end of file diff --git a/public/css/dark.75fd91ad1a59841fcf29a0b90b8658e3f3ac2b95fe716ddc3683fcb3db09b0b0.css b/public/css/dark.75fd91ad1a59841fcf29a0b90b8658e3f3ac2b95fe716ddc3683fcb3db09b0b0.css new file mode 100644 index 0000000..c16dbaa --- /dev/null +++ b/public/css/dark.75fd91ad1a59841fcf29a0b90b8658e3f3ac2b95fe716ddc3683fcb3db09b0b0.css @@ -0,0 +1,168 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: yellow; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.810e56b5e60f1cbf32ca0fecac606843178be7e6948856990563e697d7eac084.css b/public/css/dark.810e56b5e60f1cbf32ca0fecac606843178be7e6948856990563e697d7eac084.css new file mode 100644 index 0000000..b90a010 --- /dev/null +++ b/public/css/dark.810e56b5e60f1cbf32ca0fecac606843178be7e6948856990563e697d7eac084.css @@ -0,0 +1,176 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: "Lucida Console"; + font-size: 21px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.815a28b4abfc356042b23d920d1aabfe7f4e0587eeeaa4fcca9597e8fe80a31d.css b/public/css/dark.815a28b4abfc356042b23d920d1aabfe7f4e0587eeeaa4fcca9597e8fe80a31d.css new file mode 100644 index 0000000..0562fa2 --- /dev/null +++ b/public/css/dark.815a28b4abfc356042b23d920d1aabfe7f4e0587eeeaa4fcca9597e8fe80a31d.css @@ -0,0 +1,180 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + background-color: darkblue; + border-color: darkblue; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.82610263048c2b87eb2912614c320cfca902b6cdcf9a9288b5816c5ea545699f.css b/public/css/dark.82610263048c2b87eb2912614c320cfca902b6cdcf9a9288b5816c5ea545699f.css new file mode 100644 index 0000000..03f6d86 --- /dev/null +++ b/public/css/dark.82610263048c2b87eb2912614c320cfca902b6cdcf9a9288b5816c5ea545699f.css @@ -0,0 +1,174 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: italic; + font-family: Georgia, "Times New Roman", serif; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.82f2f83e158df3716afd11f528064d908bb886ea20970e6355ed93ddabe741a0.css b/public/css/dark.82f2f83e158df3716afd11f528064d908bb886ea20970e6355ed93ddabe741a0.css new file mode 100644 index 0000000..f7e67f3 --- /dev/null +++ b/public/css/dark.82f2f83e158df3716afd11f528064d908bb886ea20970e6355ed93ddabe741a0.css @@ -0,0 +1,162 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.85d74ce5ba682cb06f15d83220855b18b81d55cb154f26c2cf7625059ee955ec.css b/public/css/dark.85d74ce5ba682cb06f15d83220855b18b81d55cb154f26c2cf7625059ee955ec.css new file mode 100644 index 0000000..47fb913 --- /dev/null +++ b/public/css/dark.85d74ce5ba682cb06f15d83220855b18b81d55cb154f26c2cf7625059ee955ec.css @@ -0,0 +1,171 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-top: 1px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.8a5fc4abddac3a95da7e5a8cb65d4525ea1e8dd1e5b1efef0635700e0aa6cb3a.css b/public/css/dark.8a5fc4abddac3a95da7e5a8cb65d4525ea1e8dd1e5b1efef0635700e0aa6cb3a.css new file mode 100644 index 0000000..1f4ed96 --- /dev/null +++ b/public/css/dark.8a5fc4abddac3a95da7e5a8cb65d4525ea1e8dd1e5b1efef0635700e0aa6cb3a.css @@ -0,0 +1,176 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: "Lucida Console"; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.8b87a700d7f7c902cb49416c2b9c8efb9ee1f060d9346445386dedad83f79107.css b/public/css/dark.8b87a700d7f7c902cb49416c2b9c8efb9ee1f060d9346445386dedad83f79107.css new file mode 100644 index 0000000..7cdef59 --- /dev/null +++ b/public/css/dark.8b87a700d7f7c902cb49416c2b9c8efb9ee1f060d9346445386dedad83f79107.css @@ -0,0 +1,162 @@ +body { + color: white; + background-color: #202124; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} +.main-container { + max-width: 150%; +} \ No newline at end of file diff --git a/public/css/dark.987fb061ab00dd4e7e881eaa01435d301293cb0a72d71e50faf2b4f951365265.css b/public/css/dark.987fb061ab00dd4e7e881eaa01435d301293cb0a72d71e50faf2b4f951365265.css new file mode 100644 index 0000000..f02b117 --- /dev/null +++ b/public/css/dark.987fb061ab00dd4e7e881eaa01435d301293cb0a72d71e50faf2b4f951365265.css @@ -0,0 +1,179 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + background-color: lightblue; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.9893f2583c1c14fc26498242465d353e84b1a62c96c457355a760435c7b19632.css b/public/css/dark.9893f2583c1c14fc26498242465d353e84b1a62c96c457355a760435c7b19632.css new file mode 100644 index 0000000..1c19ff4 --- /dev/null +++ b/public/css/dark.9893f2583c1c14fc26498242465d353e84b1a62c96c457355a760435c7b19632.css @@ -0,0 +1,171 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-top: 10px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.a5ae6988b4c088d85390187e2642a55cb489357a5fe0a0c9b26d5c6109bc6661.css b/public/css/dark.a5ae6988b4c088d85390187e2642a55cb489357a5fe0a0c9b26d5c6109bc6661.css new file mode 100644 index 0000000..faeeb87 --- /dev/null +++ b/public/css/dark.a5ae6988b4c088d85390187e2642a55cb489357a5fe0a0c9b26d5c6109bc6661.css @@ -0,0 +1,160 @@ +body { + color: white; + background-color: #202124; + size: auto; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.c3a51c9b82ab68875dc684fe0c269d1840a0ae707de0c824168dba0583353e16.css b/public/css/dark.c3a51c9b82ab68875dc684fe0c269d1840a0ae707de0c824168dba0583353e16.css new file mode 100644 index 0000000..4bd8ee9 --- /dev/null +++ b/public/css/dark.c3a51c9b82ab68875dc684fe0c269d1840a0ae707de0c824168dba0583353e16.css @@ -0,0 +1,178 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul.a{ +background-color: lightblue; +} +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.de830a1959e4408be53c041b2e3444da65347e263a0145e7f18dc8dbbba5238f.css b/public/css/dark.de830a1959e4408be53c041b2e3444da65347e263a0145e7f18dc8dbbba5238f.css new file mode 100644 index 0000000..51d8ace --- /dev/null +++ b/public/css/dark.de830a1959e4408be53c041b2e3444da65347e263a0145e7f18dc8dbbba5238f.css @@ -0,0 +1,171 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; + background-color: #FCF5E5; + font-family: "Roboto Mono"; + min-height: 40px; + padding-left: 48px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.df40051c0b108f1bdf8667b9afa8f7eaba9485c25df9146d1e2682091a3e5bd8.css b/public/css/dark.df40051c0b108f1bdf8667b9afa8f7eaba9485c25df9146d1e2682091a3e5bd8.css new file mode 100644 index 0000000..c37060e --- /dev/null +++ b/public/css/dark.df40051c0b108f1bdf8667b9afa8f7eaba9485c25df9146d1e2682091a3e5bd8.css @@ -0,0 +1,180 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + background-color: darkblue; + border-color: red; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.e8ddd8f7f38de809b6bbec37dc2c06268bad25e00fed2af1e82c0376428c087b.css b/public/css/dark.e8ddd8f7f38de809b6bbec37dc2c06268bad25e00fed2af1e82c0376428c087b.css new file mode 100644 index 0000000..792dd64 --- /dev/null +++ b/public/css/dark.e8ddd8f7f38de809b6bbec37dc2c06268bad25e00fed2af1e82c0376428c087b.css @@ -0,0 +1,180 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + background-color: darkblue; + list-style-type: square; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.f43a3c68418667699602352c2aca6814ffac7a3671458224f422ba4847537c26.css b/public/css/dark.f43a3c68418667699602352c2aca6814ffac7a3671458224f422ba4847537c26.css new file mode 100644 index 0000000..412b441 --- /dev/null +++ b/public/css/dark.f43a3c68418667699602352c2aca6814ffac7a3671458224f422ba4847537c26.css @@ -0,0 +1,162 @@ +body { + color: white; + background-color: #202124; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: blue; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} +.main-container { + max-width: 100%; +} \ No newline at end of file diff --git a/public/css/dark.f9519a56dc0855aaca9902e59a78386380a507a4d28e9e4d4837827edcb3e5a6.css b/public/css/dark.f9519a56dc0855aaca9902e59a78386380a507a4d28e9e4d4837827edcb3e5a6.css new file mode 100644 index 0000000..4e9c1c6 --- /dev/null +++ b/public/css/dark.f9519a56dc0855aaca9902e59a78386380a507a4d28e9e4d4837827edcb3e5a6.css @@ -0,0 +1,176 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-family: monospace; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.faafb78cbb931ae92c7afba7eaff01561a7add10bab441c222612dd79021bedf.css b/public/css/dark.faafb78cbb931ae92c7afba7eaff01561a7add10bab441c222612dd79021bedf.css new file mode 100644 index 0000000..d73e917 --- /dev/null +++ b/public/css/dark.faafb78cbb931ae92c7afba7eaff01561a7add10bab441c222612dd79021bedf.css @@ -0,0 +1,180 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; + font-family: 'IBM Plex Mono', monospace; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + border-color: red; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/dark.fed26201f04e39f75aae002932b13867991dd69bbae5fdc69be7d46698803350.css b/public/css/dark.fed26201f04e39f75aae002932b13867991dd69bbae5fdc69be7d46698803350.css new file mode 100644 index 0000000..b03f9a5 --- /dev/null +++ b/public/css/dark.fed26201f04e39f75aae002932b13867991dd69bbae5fdc69be7d46698803350.css @@ -0,0 +1,180 @@ +body { + color: white; + background-color: #202124; + margin: 0; + padding: 0; + position: relative; +} + +::-moz-selection { + background: blue; + color: #fff; + text-shadow: none; +} + +::selection { + background: red; + color: #fff; + text-shadow: none; +} + +hr { + border-top: 3px dotted blue; +} +code { + background-color: lightblue; + color: black; + text-decoration: bold; + padding: 0.1em 0.2em; +} +pre { + background-color: #272822; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #ddd; +} +h1::before { + color: var(--darkMaincolor); + content: "# "; +} +h2::before { + color: var(--darkMaincolor); + content: "## "; +} +h3::before { + color: var(--darkMaincolor); + content: "### "; +} +h4::before { + color: var(--darkMaincolor); + content: "#### "; +} +h5::before { + color: var(--darkMaincolor); + content: "##### "; +} +h6::before { + color: var(--darkMaincolor); + content: "###### "; +} + +a { + border-bottom: 3px solid var(--darkMaincolor); + color: inherit; +} +a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +ul { + background-color: lightblue; + list-style-type: square; +} + +.site-description a { + color: #ddd; +} +.site-description a:hover { + color: black; +} + +.tags a { + border-bottom: 3px solid var(--darkMaincolor); +} +.tags a:hover { + background-color: var(--darkMaincolor); + color: black; +} + +.site-title a { + color: white; + text-decoration: none !important; +} + +.site-toc a { + colour: purple; + +} + +.header nav, +.footer { + border-color: #333; +} + +.highlight { + background-color: #333; +} +.soc:hover { + color: black; +} +.draft-label { + color: var(--darkMaincolor); + background-color: blue; +} +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { + content: "js"; + background: #f7df1e; + color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { + content: 'yaml'; + background: #f71e6a; + color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { + content: 'shell'; + background: green; + color:white +} +.highlight pre code[class*='language-json']::before{ + content: 'json'; + background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { + content: 'py'; + background: blue; + color: yellow ; +} +.highlight pre code[class*='language-css']::before{ + content: 'css'; + background: cyan; + color: black ; +} +.highlight pre code[class*='language-go']::before{ + content: 'Go'; + background: cyan; + color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ + content: 'Markdown'; + background: royalblue; + color: whitesmoke ; +} diff --git a/public/css/fonts.005298b624c67c53a2c807c4aca45625ce1e4db593dc295c06773b1563c3437c.css b/public/css/fonts.005298b624c67c53a2c807c4aca45625ce1e4db593dc295c06773b1563c3437c.css new file mode 100644 index 0000000..36d446d --- /dev/null +++ b/public/css/fonts.005298b624c67c53a2c807c4aca45625ce1e4db593dc295c06773b1563c3437c.css @@ -0,0 +1,45 @@ +/* fira-sans-regular - latin */ +@font-face { + font-display: swap; + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 400; + src: url('../fonts/fira-sans-v10-latin-regular.eot'); /* IE9 Compat Modes */ + src: local('Fira Sans Regular'), local('FiraSans-Regular'), + url('../fonts/fira-sans-v10-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/fira-sans-v10-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/fira-sans-v10-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/fira-sans-v10-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/fira-sans-v10-latin-regular.svg#FiraSans') format('svg'); /* Legacy iOS */ +} +/* roboto-mono-regular - latin */ +@font-face { + font-display: swap; + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + src: url('../fonts/roboto-mono-v12-latin-regular.eot'); /* IE9 Compat Modes */ + src: url('../fonts/roboto-mono-v12-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/roboto-mono-v12-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/roboto-mono-v12-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/roboto-mono-v12-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/roboto-mono-v12-latin-regular.svg#RobotoMono') format('svg'); /* Legacy iOS */ +} +/* ibm-plex-mono-500italic - latin */ +@font-face { + font-display: swap; + font-family: 'IBM Plex Mono'; + font-style: italic; + font-weight: 500; + src: url('../fonts/ibm-plex-mono-v6-latin-500italic.eot'); /* IE9 Compat Modes */ + src: local('IBM Plex Mono Medium Italic'), local('IBMPlexMono-MediumItalic'), + url('../fonts/ibm-plex-mono-v6-latin-500italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.svg#IBMPlexMono') format('svg'); /* Legacy iOS */ +} + +@page { + size: auto; +} diff --git a/public/css/fonts.2c2227b81b1970a03e760aa2e6121cd01f87c88586803cbb282aa224720a765f.css b/public/css/fonts.2c2227b81b1970a03e760aa2e6121cd01f87c88586803cbb282aa224720a765f.css new file mode 100644 index 0000000..f758f58 --- /dev/null +++ b/public/css/fonts.2c2227b81b1970a03e760aa2e6121cd01f87c88586803cbb282aa224720a765f.css @@ -0,0 +1,41 @@ +/* fira-sans-regular - latin */ +@font-face { + font-display: swap; + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 400; + src: url('../fonts/fira-sans-v10-latin-regular.eot'); /* IE9 Compat Modes */ + src: local('Fira Sans Regular'), local('FiraSans-Regular'), + url('../fonts/fira-sans-v10-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/fira-sans-v10-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/fira-sans-v10-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/fira-sans-v10-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/fira-sans-v10-latin-regular.svg#FiraSans') format('svg'); /* Legacy iOS */ +} +/* roboto-mono-regular - latin */ +@font-face { + font-display: swap; + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + src: url('../fonts/roboto-mono-v12-latin-regular.eot'); /* IE9 Compat Modes */ + src: url('../fonts/roboto-mono-v12-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/roboto-mono-v12-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/roboto-mono-v12-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/roboto-mono-v12-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/roboto-mono-v12-latin-regular.svg#RobotoMono') format('svg'); /* Legacy iOS */ +} +/* ibm-plex-mono-500italic - latin */ +@font-face { + font-display: swap; + font-family: 'IBM Plex Mono'; + font-style: italic; + font-weight: 500; + src: url('../fonts/ibm-plex-mono-v6-latin-500italic.eot'); /* IE9 Compat Modes */ + src: local('IBM Plex Mono Medium Italic'), local('IBMPlexMono-MediumItalic'), + url('../fonts/ibm-plex-mono-v6-latin-500italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/ibm-plex-mono-v6-latin-500italic.svg#IBMPlexMono') format('svg'); /* Legacy iOS */ +} diff --git a/public/css/main.0d5cba023746c2c38d3cd1c662f9d83425631d0ee6fe12ec14777c8a515a53f0.css b/public/css/main.0d5cba023746c2c38d3cd1c662f9d83425631d0ee6fe12ec14777c8a515a53f0.css new file mode 100644 index 0000000..72eabc2 --- /dev/null +++ b/public/css/main.0d5cba023746c2c38d3cd1c662f9d83425631d0ee6fe12ec14777c8a515a53f0.css @@ -0,0 +1,339 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Block quote*/ +blockquote { + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} + + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.1a1c276e8e001ffab66769e2276c3c2d1f7cf35b66902dbd9bb1676c99eafdd2.css b/public/css/main.1a1c276e8e001ffab66769e2276c3c2d1f7cf35b66902dbd9bb1676c99eafdd2.css new file mode 100644 index 0000000..d7e833e --- /dev/null +++ b/public/css/main.1a1c276e8e001ffab66769e2276c3c2d1f7cf35b66902dbd9bb1676c99eafdd2.css @@ -0,0 +1,338 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Block quote*/ +blockquote { + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} + + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.7534bb61a5f169e92170d3cd6a3ecc130e9170759644b8c32e623544c5585844.css b/public/css/main.7534bb61a5f169e92170d3cd6a3ecc130e9170759644b8c32e623544c5585844.css new file mode 100644 index 0000000..5d6d966 --- /dev/null +++ b/public/css/main.7534bb61a5f169e92170d3cd6a3ecc130e9170759644b8c32e623544c5585844.css @@ -0,0 +1,341 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Block quote*/ +blockquote { + border-color: red; + background-color: #FCF5E5; + color: black; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-family: 'Fira Sans', sans-serif; + font-size: 18px; + font-weight: 400; +} + + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.91d65420c7ab8e5a0751189a5e8af78a25dbb2b223ad9da6c658457a49db4fcc.css b/public/css/main.91d65420c7ab8e5a0751189a5e8af78a25dbb2b223ad9da6c658457a49db4fcc.css new file mode 100644 index 0000000..69dc69a --- /dev/null +++ b/public/css/main.91d65420c7ab8e5a0751189a5e8af78a25dbb2b223ad9da6c658457a49db4fcc.css @@ -0,0 +1,339 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Block quote*/ +/* +blockquote { + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} +*/ + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.934c0142beb9896e6e8d4ff59f31da5765d38a2f820db643367eb88951eaacec.css b/public/css/main.934c0142beb9896e6e8d4ff59f31da5765d38a2f820db643367eb88951eaacec.css new file mode 100644 index 0000000..2a6e16d --- /dev/null +++ b/public/css/main.934c0142beb9896e6e8d4ff59f31da5765d38a2f820db643367eb88951eaacec.css @@ -0,0 +1,341 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Block quote*/ +blockquote { + border-color: red; + background-color: #FCF5E5; + color: black; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} + + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.9fd1b17b0c5dbaabf28d8df43357261e49c5fd4abcb6fb3e8f6b894a7b567020.css b/public/css/main.9fd1b17b0c5dbaabf28d8df43357261e49c5fd4abcb6fb3e8f6b894a7b567020.css new file mode 100644 index 0000000..adf02fb --- /dev/null +++ b/public/css/main.9fd1b17b0c5dbaabf28d8df43357261e49c5fd4abcb6fb3e8f6b894a7b567020.css @@ -0,0 +1,339 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400 +} + + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.ac08a4c9714baa859217f92f051deb58df2938ec352b506df655005dcaf98cc0.css b/public/css/main.ac08a4c9714baa859217f92f051deb58df2938ec352b506df655005dcaf98cc0.css new file mode 100644 index 0000000..3a7d1cd --- /dev/null +++ b/public/css/main.ac08a4c9714baa859217f92f051deb58df2938ec352b506df655005dcaf98cc0.css @@ -0,0 +1,333 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +blockquote { + border-left: 3px solid var(--bordercl); + color: #737373; + margin: 0; + padding-left: 1em; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.bcf17f9cab83d6543f2b009e550cb13eeae4c0f4b14ebf3b3387c0eb6b31e2f5.css b/public/css/main.bcf17f9cab83d6543f2b009e550cb13eeae4c0f4b14ebf3b3387c0eb6b31e2f5.css new file mode 100644 index 0000000..ec9d807 --- /dev/null +++ b/public/css/main.bcf17f9cab83d6543f2b009e550cb13eeae4c0f4b14ebf3b3387c0eb6b31e2f5.css @@ -0,0 +1,340 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; + font-family: 'IBM Plex Mono', monospace; +} + + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.d2c808c739be45b09d87ce610236487fce3c29ccf592ee0516f7ffaa4db29b9c.css b/public/css/main.d2c808c739be45b09d87ce610236487fce3c29ccf592ee0516f7ffaa4db29b9c.css new file mode 100644 index 0000000..d395c9e --- /dev/null +++ b/public/css/main.d2c808c739be45b09d87ce610236487fce3c29ccf592ee0516f7ffaa4db29b9c.css @@ -0,0 +1,339 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +blockquote { + border-color: red; + background-color: #FCF5E5; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} + + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.d30942d7b852759fe0cd3ab0f8aac39d3a8967a463b17c2bea1ae5d4ab98723f.css b/public/css/main.d30942d7b852759fe0cd3ab0f8aac39d3a8967a463b17c2bea1ae5d4ab98723f.css new file mode 100644 index 0000000..8c356f6 --- /dev/null +++ b/public/css/main.d30942d7b852759fe0cd3ab0f8aac39d3a8967a463b17c2bea1ae5d4ab98723f.css @@ -0,0 +1,337 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +blockquote { + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} + + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.d368da5fb2879cd885463b5df2cf4640cb2a7a92b2c9d6bc09e6f3e3b0c3fea8.css b/public/css/main.d368da5fb2879cd885463b5df2cf4640cb2a7a92b2c9d6bc09e6f3e3b0c3fea8.css new file mode 100644 index 0000000..cdcbad3 --- /dev/null +++ b/public/css/main.d368da5fb2879cd885463b5df2cf4640cb2a7a92b2c9d6bc09e6f3e3b0c3fea8.css @@ -0,0 +1,341 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Block quote*/ +blockquote { + border-color: red; + background-color: #FCF5E5; + color: black; + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-family: 'Roboto Mono', monospace; + font-size: 18px; + font-weight: 400; +} + + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/css/main.dfe5070817b04a13a298537b0cebd9848be70bceaee82a94c15c988d681d550b.css b/public/css/main.dfe5070817b04a13a298537b0cebd9848be70bceaee82a94c15c988d681d550b.css new file mode 100644 index 0000000..85fccc6 --- /dev/null +++ b/public/css/main.dfe5070817b04a13a298537b0cebd9848be70bceaee82a94c15c988d681d550b.css @@ -0,0 +1,338 @@ +/* Markdown */ +:root{ +--maincolor: red; +--bordercl:rebeccapurple; +--callouctcolor:dodgerblue; +--hovercolor:navy; +--darkMaincolor: #50fa7b; +} +html { + color: #232333; + font-family: 'Roboto Mono', monospace; + font-size: 15px; + line-height: 1.6em; +} +body{ + display: block; + margin: 8px; +} +* { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +::selection { + background: var(--maincolor); + color: #fff; +} + +p { + font-family: 'Fira Sans', sans-serif; + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px dotted var(--bordercl); + margin: 1em 0; +} + +a { + border-bottom: 3px solid var(--maincolor); + color: inherit; + text-decoration: none; +} +a:hover { + background-color: var(--hovercolor); + color: #fff; +} + +ul { + list-style: none; + padding-left: 2ch; +} +ul li { + text-indent: -2ch; +} +ul > li::before { + content: '* '; + font-weight: bold; +} + +/* Images */ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} +figure h4::before { + content: '↳ '; +} + +/* Code blocks */ +code { + background-color: #f1f1f1; + padding: .1em .2em; +} + +pre { + background-color: #ececec; + line-height: 1.4; + overflow-x: auto; + padding: 1em; +} + +.highlight pre ::selection { + background: rgba(255, 255, 255, 0.2); + color: inherit; +} + +pre code { + background-color: transparent; + color: inherit; + font-size: 100%; + padding: 0; +} + +/* Block quote +blockquote { + min-height: 40px; + padding-left: 48px; + padding-block-start: 1px; + padding-block-end: 1px; + font-style: normal; + font-size: 18px; + font-weight: 400; +} + + +/* Containers */ +.content { + margin-bottom: 4em; + margin-left: auto; + margin-right: auto; + max-width: 800px; + padding: 0 1ch; + word-wrap: break-word; +} + +/* Header */ +header { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + margin: 1em 0; + line-height: 2.5em; +} + +header .main { + font-size: 1.5rem; +} +h1, h2, h3, h4, h5, h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { color: var(--maincolor); content: '# '; } +h2::before { color: var(--maincolor); content: '## '; } +h3::before { color: var(--maincolor); content: '### '; } +h4::before { color: var(--maincolor); content: '#### '; } +h5::before { color: var(--maincolor); content: '##### '; } +h6::before { color: var(--maincolor); content: '###### '; } + +.meta { + color: #999; + letter-spacing: -0.5px; +} + +/* Footer */ +footer { + display: flex; + align-items: center; + border-top: 0.4rem dotted var(--bordercl); + padding: 2rem 0rem; + margin-top: 2rem; +} +.soc { + display: flex; + align-items: center; + border-bottom: none; +} +.border { + margin-left: 0.5rem; + margin-right: 0.5rem; + border: 1px solid; +} +.footer-info { + padding: var(--footer-padding); +} + +/* Common */ +.title h1 { + margin-bottom: 0; +} + +time { + color: grey; +} + +/* Posts */ +article .title { + margin-bottom: 1em; +} + + +/* Callout */ +.callout { + background-color: var(--callouctcolor); + color: #fff; + padding: 1em; +} + +.callout p { + font-family: 'IBM Plex Mono', monospace; + margin: 0; +} + +.callout a { + border-bottom: 3px solid #fff; +} + +.callout a:hover { + background-color: #fff; + color: var(--callouctcolor); +} + +.site-description { +display: flex; +justify-content: space-between; +} +.tags li::before{ + content: "🏷 "; +} +.tags a{ + border-bottom: 3px solid var(--maincolor); +} +.tags a:hover{ + color:white; + background-color: var(--hovercolor); +} +svg{ + max-height: 15px; +} +.soc:hover{ + color: white; +} +.draft-label{ + color: var(--bordercl); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: #f9f2f4; +} +.highlight { + position: relative; + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"] { + -webkit-overflow-scrolling: touch; +} +.highlight pre code[class*="language-"]::before { + background: black; + border-radius: 0 0 0.25rem 0.25rem; + color: white; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + position: absolute; + right: 1rem; + text-align: right; + text-transform: uppercase; + top: 0; +} + +.highlight pre code[class=language-javaScript]::before, +.highlight pre code[class="language-js"]::before { +content: "js"; +background: #f7df1e; +color: black; +} +.highlight pre code[class*='language-yml']::before, +.highlight pre code[class*='language-yaml']::before { +content: 'yaml'; +background: #f71e6a; +color: white; +} +.highlight pre code[class*='language-shell']::before, +.highlight pre code[class*='language-bash']::before, +.highlight pre code[class*='language-sh']::before { +content: 'shell'; +background: green; +color:white +} +.highlight pre code[class*='language-json']::before{ +content: 'json'; +background: dodgerblue; + color: #000000 +} +.highlight pre code[class*='language-python']::before, +.highlight pre code[class*='language-py']::before { +content: 'py'; +background: blue; +color: yellow ; +} +.highlight pre code[class*='language-css']::before{ +content: 'css'; +background: cyan; +color: black ; +} +.highlight pre code[class*='language-go']::before{ +content: 'Go'; +background: cyan; +color: royalblue ; +} +.highlight pre code[class*='language-md']::before, +.highlight pre code[class*='language-md']::before{ +content: 'Markdown'; +background: royalblue; +color: whitesmoke ; +} + +/* table */ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th{ + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td{ + padding: 6px 13px; + border: 1px solid #dfe2e5; +} diff --git a/public/data/taskmaster.db b/public/data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/public/data/taskmaster.db differ diff --git a/public/fearlessness-how-to-stop-running-from-space/index.html b/public/fearlessness-how-to-stop-running-from-space/index.html new file mode 100644 index 0000000..0a4b849 --- /dev/null +++ b/public/fearlessness-how-to-stop-running-from-space/index.html @@ -0,0 +1,141 @@ + + + + Fearlessness: How to Stop Running from Space - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Fearlessness: How to Stop Running from Space

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos.

+

We are afraid of empty space in our lives.

+

The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives.

+

We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. We try to fill every second with activity, with something useful, as if silence and space are not valuable.

+

But what are we afraid of?

+

And who would we be if we didn’t have that fear?

+

We’re afraid of space and stillness and silence because it highlights the uncertainty, instability, groundlessness, insecurity, shakiness that lie underneath every second of our lives. We’re afraid of having to face this instability and uncertainty, of having to feel the fear of it.

+

Without the fear of all of the uncertainty that is highlighted by space … we become free.

+

I know in my life, when I allow myself to have stillness, silence, solitude, simplicity and space … it leaves room to face whatever is coming up for me. It gives me room to fully feel any feelings that I’ve been avoiding. It allows me to be more honest with myself, instead of using distractions and busyness to cover up what I don’t want to see.

+

And in the end, I develop trust that the space is not something to be feared, but rather something to be treasured. A gift, filled with learning and not knowing and shakiness and beauty.

+

You might try allowing more space to be in your day, without filling it:

+
    +
  • Take some time between tasks for stillness.
  • +
  • Sit out in nature, in silence, without technology.
  • +
  • When you notice yourself reaching for your phone, pause. See if you can just be still, just savor some space.
  • +
  • When you feel uncertainty or instability in your life (hint: it’s always there), let yourself feel it. Be present with it, without needing to run or avoid.
  • +
  • When you feel fear, be open-hearted with it and allow yourself fully feel it, being friendly with it. Your relationship with fear will change if you become friendly with it.
  • +
  • Do less, and trust that things won’t fall apart. Or if they do fall apart, you can be present with that instability.
  • +
  • When you’re in line, driving, eating, walking, exercising … see if you can do those things in silence, without technology, without needing to do something “useful.” Find the value in these spaces.
  • +
  • Notice who you are without the fear of space.
  • +
+

Savor these spaces, their deliciousness. Savor the groundlessness, as something filled with freedom if we learn not to fear it. Be present with the fear and uncertainty, as good friends not as enemies.

+

Let your heart be open raw tender and vulnerable, and your mind embracing the spaciousness of the vast blue sky of open awareness.

+ +
+ + +
+
+ +
+ + diff --git a/public/fonts/fira-sans-v10-latin-regular.eot b/public/fonts/fira-sans-v10-latin-regular.eot new file mode 100644 index 0000000..7abf4c2 Binary files /dev/null and b/public/fonts/fira-sans-v10-latin-regular.eot differ diff --git a/public/fonts/fira-sans-v10-latin-regular.svg b/public/fonts/fira-sans-v10-latin-regular.svg new file mode 100644 index 0000000..1e52097 --- /dev/null +++ b/public/fonts/fira-sans-v10-latin-regular.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fira-sans-v10-latin-regular.ttf b/public/fonts/fira-sans-v10-latin-regular.ttf new file mode 100644 index 0000000..572e442 Binary files /dev/null and b/public/fonts/fira-sans-v10-latin-regular.ttf differ diff --git a/public/fonts/fira-sans-v10-latin-regular.woff b/public/fonts/fira-sans-v10-latin-regular.woff new file mode 100644 index 0000000..d99ba57 Binary files /dev/null and b/public/fonts/fira-sans-v10-latin-regular.woff differ diff --git a/public/fonts/fira-sans-v10-latin-regular.woff2 b/public/fonts/fira-sans-v10-latin-regular.woff2 new file mode 100644 index 0000000..9bb5760 Binary files /dev/null and b/public/fonts/fira-sans-v10-latin-regular.woff2 differ diff --git a/public/fonts/ibm-plex-mono-v6-latin-500italic.eot b/public/fonts/ibm-plex-mono-v6-latin-500italic.eot new file mode 100644 index 0000000..62b89b3 Binary files /dev/null and b/public/fonts/ibm-plex-mono-v6-latin-500italic.eot differ diff --git a/public/fonts/ibm-plex-mono-v6-latin-500italic.svg b/public/fonts/ibm-plex-mono-v6-latin-500italic.svg new file mode 100644 index 0000000..6423805 --- /dev/null +++ b/public/fonts/ibm-plex-mono-v6-latin-500italic.svg @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/ibm-plex-mono-v6-latin-500italic.ttf b/public/fonts/ibm-plex-mono-v6-latin-500italic.ttf new file mode 100644 index 0000000..e4d1ddf Binary files /dev/null and b/public/fonts/ibm-plex-mono-v6-latin-500italic.ttf differ diff --git a/public/fonts/ibm-plex-mono-v6-latin-500italic.woff b/public/fonts/ibm-plex-mono-v6-latin-500italic.woff new file mode 100644 index 0000000..4504b41 Binary files /dev/null and b/public/fonts/ibm-plex-mono-v6-latin-500italic.woff differ diff --git a/public/fonts/ibm-plex-mono-v6-latin-500italic.woff2 b/public/fonts/ibm-plex-mono-v6-latin-500italic.woff2 new file mode 100644 index 0000000..489745d Binary files /dev/null and b/public/fonts/ibm-plex-mono-v6-latin-500italic.woff2 differ diff --git a/public/fonts/roboto-mono-v12-latin-regular.eot b/public/fonts/roboto-mono-v12-latin-regular.eot new file mode 100644 index 0000000..8c56483 Binary files /dev/null and b/public/fonts/roboto-mono-v12-latin-regular.eot differ diff --git a/public/fonts/roboto-mono-v12-latin-regular.svg b/public/fonts/roboto-mono-v12-latin-regular.svg new file mode 100644 index 0000000..1864328 --- /dev/null +++ b/public/fonts/roboto-mono-v12-latin-regular.svg @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/roboto-mono-v12-latin-regular.ttf b/public/fonts/roboto-mono-v12-latin-regular.ttf new file mode 100644 index 0000000..d5dee83 Binary files /dev/null and b/public/fonts/roboto-mono-v12-latin-regular.ttf differ diff --git a/public/fonts/roboto-mono-v12-latin-regular.woff b/public/fonts/roboto-mono-v12-latin-regular.woff new file mode 100644 index 0000000..f319fbf Binary files /dev/null and b/public/fonts/roboto-mono-v12-latin-regular.woff differ diff --git a/public/fonts/roboto-mono-v12-latin-regular.woff2 b/public/fonts/roboto-mono-v12-latin-regular.woff2 new file mode 100644 index 0000000..ed384d2 Binary files /dev/null and b/public/fonts/roboto-mono-v12-latin-regular.woff2 differ diff --git a/public/getting-started-with-traveling-ultralight/index.html b/public/getting-started-with-traveling-ultralight/index.html new file mode 100644 index 0000000..fce413c --- /dev/null +++ b/public/getting-started-with-traveling-ultralight/index.html @@ -0,0 +1,116 @@ + + + + Getting Started with Traveling Ultralight - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Getting Started with Traveling Ultralight

+
Posted on 2020-03-18 DRAFT
+
+ + +
+

I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said.

+

I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. But then I remembered that I’m far from normal in this way.

+

I gave him a tip for getting started, and I recommend it for all of you, who want to travel light — or ultralight, as I call it, because for many people traveling light is taking a carry-on roller luggage. For me, having those roller bags is lugging too much, because you can run up stairs with it with ease, or carry it all over a city without worrying about stowing away your luggage somewhere first. It’s so much easier to travel ultralight.

+

Here’s the tip I gave him to get started: start by getting a small backpack (less than 20 liters) and then just travel with what fits in that.

+

That’s how to start. But you’ll probably want some guidance on what to put into the bag, and how to travel with so little. Here’s some guidance to get started:

+
    +
  • I travel with a lightweight laptop (Macbook Air), a few clothes, my phone, earbuds and some charging cords, toiletries, and almost nothing else. A lightweight windbreaker for wind and light rain (Patagonia Houdini). An eye mask and ear plugs. A collapsible water bottle. My passport. That’s about it. No extra shoes. No books. No suit. No travel pillow. No extra camera other than my phone. I’m not sure what else everyone else brings, but none of that.
  • +
  • I bring clothes that I can wash in the sink or shower and that will dry overnight. Lightweight stuff that I can layer. Often they’re workout-style clothes or things from companies like Outlier or Patagonia that travel well. I don’t bring enough underwear or socks for every day of the trip, because I wash them every couple of days. I only bring one or two extra T-shirts, generally wearing the same two shirts the whole trip, even if it’s a month long. No one has ever once cared what I wear when I’m traveling.
  • +
  • I bring minimal toiletries: a small shaver for my head, razor, toothbrush, floss small tubes of toothpaste and shaving cream, deodorant, nail clippers, ibuprofen.
  • +
  • For cold places, I have thermal underwear and a couple long-sleeve layers (generally all Patagonia capilene stuff), and a beanie. I don’t usually go to places where it’s snowing (I don’t know why, maybe snow isn’t my thing), so I don’t have clothes to deal with that weather.
  • +
  • For warm places, I will bring flip flops and swim trunks, and leave most of the colder layers behind.
  • +
+

That’s enough for a monthlong trip, which I’ve done multiple times with this kind of setup. For a shorter trip of a few days, I might bring even less.

+

I really love traveling this way, and am more than willing to sacrifice bringing extra things for the luxury of traveling lightweight.

+

By the way, you don’t need much more than this kind of setup even in everyday life.

+

For more info on this, check out my Ultralight ebook, and my friend Tynan has a great book called Forever Nomad.

+ +
+ + +
+
+ +
+ + diff --git a/public/hello-r-markdown/index.Rmd b/public/hello-r-markdown/index.Rmd new file mode 100644 index 0000000..8768d78 --- /dev/null +++ b/public/hello-r-markdown/index.Rmd @@ -0,0 +1,38 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(collapse = TRUE) +``` + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + +```{r cars} +summary(cars) +fit <- lm(dist ~ speed, data = cars) +fit +``` + +# Including Plots + +You can also embed plots. See Figure \@ref(fig:pie) for example: + +```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE} +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` diff --git a/public/hello-r-markdown/index.html b/public/hello-r-markdown/index.html new file mode 100644 index 0000000..3497040 --- /dev/null +++ b/public/hello-r-markdown/index.html @@ -0,0 +1,151 @@ + + + + Hello R Markdown - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Hello R Markdown

+
Posted on 2020-12-01 DRAFT
+
+ + +
+

R Markdown

+

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

+

You can embed an R code chunk like this:

+
summary(cars)
+##      speed           dist       
+##  Min.   : 4.0   Min.   :  2.00  
+##  1st Qu.:12.0   1st Qu.: 26.00  
+##  Median :15.0   Median : 36.00  
+##  Mean   :15.4   Mean   : 42.98  
+##  3rd Qu.:19.0   3rd Qu.: 56.00  
+##  Max.   :25.0   Max.   :120.00
+fit <- lm(dist ~ speed, data = cars)
+fit
+## 
+## Call:
+## lm(formula = dist ~ speed, data = cars)
+## 
+## Coefficients:
+## (Intercept)        speed  
+##     -17.579        3.932
+

Including Plots

+

You can also embed plots. See Figure 1 for example:

+
par(mar = c(0, 1, 0, 1))
+pie(
+  c(280, 60, 20),
+  c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
+  col = c('#0292D8', '#F7EA39', '#C4B632'),
+  init.angle = -50, border = NA
+)
+
+ +
+ + +
+
+ +
+ + diff --git a/public/hello-r-markdown/index_files/figure-html/pie-1.png b/public/hello-r-markdown/index_files/figure-html/pie-1.png new file mode 100644 index 0000000..eef072f Binary files /dev/null and b/public/hello-r-markdown/index_files/figure-html/pie-1.png differ diff --git a/public/homepage/index.html b/public/homepage/index.html new file mode 100644 index 0000000..4509cf3 --- /dev/null +++ b/public/homepage/index.html @@ -0,0 +1,93 @@ + + + + - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+

+
Posted on Jan 1, 0001
+
+ + +
+

Really? Is this not the hompage editor?

+ +
+ + +
+
+ +
+ + diff --git a/public/how-i-learned-to-stop-procrastinating-love-letting-go/index.html b/public/how-i-learned-to-stop-procrastinating-love-letting-go/index.html new file mode 100644 index 0000000..911f6df --- /dev/null +++ b/public/how-i-learned-to-stop-procrastinating-love-letting-go/index.html @@ -0,0 +1,127 @@ + + + + How I Learned to Stop Procrastinating, & Love Letting Go - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

How I Learned to Stop Procrastinating, & Love Letting Go

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

The end of procrastination is the art of letting go.

+

I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done.

+

Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. It stressed me out. My work was less-than-desirable when I did it last minute. Slowly, I started to realize that procrastination wasn’t doing me any favors. In fact, it was causing me a lot of grief.

+

But I couldn’t quit. I tried a lot of things. I tried time boxing and goal setting and accountability and the Pomodoro Technique and Getting Things Done. All are great methods, but they only last so long. Nothing really worked over the long term.

+

That’s because I wasn’t getting to the root problem.

+

I hadn’t figured out the skill that would save me from the procrastination.

+

Until I learned about letting go.

+

Letting go first came to me when I was quitting smoking. I had to let go of the “need” to smoke, the use of my crutch of cigarettes to deal with stress and problems.

+

Then I learned I needed to let go of other false needs that were causing me problems: sugar, junk food, meat, shopping, beer, possessions. I’m not saying I can never do these things again once I let go of these needs, but I let go of the idea that they’re really necessary. I let go of an unhealthy attachment to them.

+

Then I learned that distractions and the false need to check my email and news and other things online … were causing me problems. They were causing my procrastination.

+

So I learned to let go of those too.

+

Here’s the process I used to let go of the distractions and false needs that cause procrastination:

+

I paid attention to the pain they cause me, later, instead of only the temporary comfort/pleasure they gave me right away. +I thought about the person I want to be, the life I want to live. I set my intentions to do the good work I think I should do. +I watched my urges to check things, to go to the comfort of distractions. I saw that I wanted to escape discomfort of something hard, and go to the comfort of something familiar and easy. +I realized I didn’t need that comfort. I could be in discomfort and nothing bad would happen. In fact, the best things happen when I’m in discomfort. +And then I smile, and breathe, and let go.

+

And one step at a time, become the person I want to be.

+ +
+ + +
+
+ +
+ + diff --git a/public/how-to-test-dark-mode/index.html b/public/how-to-test-dark-mode/index.html new file mode 100644 index 0000000..3cbf3ff --- /dev/null +++ b/public/how-to-test-dark-mode/index.html @@ -0,0 +1,112 @@ + + + + How to test dark mode? - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

How to test dark mode?

+
Posted on 2018-03-18 DRAFT
+
+ +
+ tl;dr: + Wubba lubba dub dub +
+ +
+

You can set dark mode as default by setting params.mode to dark in config.toml or set it to auto which will detect based on your OS and switch to dark mode. For more details refer documentation

+

Here is how you can switch based on your OS

+ + +
+ + +
+
+ +
+ + diff --git a/public/hugo-shortcodes/index.html b/public/hugo-shortcodes/index.html new file mode 100644 index 0000000..7388e49 --- /dev/null +++ b/public/hugo-shortcodes/index.html @@ -0,0 +1,355 @@ + + + + Hugo shortcodes - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+ +
+ +
+ + diff --git a/public/img/The Median Duck typewriter.png b/public/img/The Median Duck typewriter.png new file mode 100644 index 0000000..5c20a02 Binary files /dev/null and b/public/img/The Median Duck typewriter.png differ diff --git a/public/img/duck_tt.png b/public/img/duck_tt.png new file mode 100644 index 0000000..8acab4c Binary files /dev/null and b/public/img/duck_tt.png differ diff --git a/public/img/logo.jpg b/public/img/logo.jpg new file mode 100644 index 0000000..4c4dba5 Binary files /dev/null and b/public/img/logo.jpg differ diff --git a/public/index.Rmd b/public/index.Rmd new file mode 100644 index 0000000..af1ebc7 --- /dev/null +++ b/public/index.Rmd @@ -0,0 +1,16 @@ +--- +title: Home Page Beta +author: Christopher Nam +menu: + header: + weight: 1 +--- + +Is this the homepage? +I hope so.... + + +So I can see this information in the description part. +How do I get it to appear in the main body of the page. + +If you see this, then you've cracked the problem! Try. \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..779b0b7 --- /dev/null +++ b/public/index.html @@ -0,0 +1,190 @@ + + + + + The Median Duck | Home + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +

vires in notitia

+ + + +
+ + + +
+

Welcome!

+

+

Welcome to The Median Duck, a self initiated project that aims to +educate and entertain the general public on data analytic topics through +the hit UK TV show Taskmaster.

+

This project is in its early stages, but great things are planned; see +this vision document for the ambitious plans that I have in mind.

+
+

Your Time Starts Now!

+
+
+
+ +
+ + +

Latest Posts

+ +
+ + + + +
+ Sidenote: Musings on TdlM + +
+ +
+ Strength in Data: Connecting to the Taskmaster Database + +
+ +
+ New Post on Archie + +
+ +
+ Hello R Markdown + +
+ +
+ Telegram Bot for GitHub Actions + +
+ +
+ Primer: When You Have Too Much to Do + +
+ +
+ Getting Started with Traveling Ultralight + +
+ +
+ How to test dark mode? + +
+ +
+ Typography + +
+ +
+ Hugo shortcodes + +
+ + + + + + +
+ + +
+ + + diff --git a/public/index.xml b/public/index.xml new file mode 100644 index 0000000..f3a129e --- /dev/null +++ b/public/index.xml @@ -0,0 +1,132 @@ + + + + The Median Duck Home Page on The Median Duck + //localhost:4321/ + Recent content in The Median Duck Home Page on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 17 Jul 2024 00:00:00 +0000 + + + Sidenote: Musings on TdlM + //localhost:4321/2024/07/data-quality-musings/ + Wed, 17 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/data-quality-musings/ + Sidenote Introduction Data Quality Why This Datasource? Potential Articles to Explore in the Future Sidenote Introduction A few remarks and musings on the Trabajo de las Mesas database (TdlM). Data Quality As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster. + + + Your Time Starts Now! + //localhost:4321/tasks/ + Wed, 17 Jul 2024 00:00:00 +0000 + //localhost:4321/tasks/ + A site about Taskmaster has got to have some tasks….surely? The Prize Task This project is self initiated and funded. If you would like to show your appreciation and gratitude in this project, feel free to donate to my buy me a coffee page. All donations are welcome. Make a donation to the aforementioned Buy Me a Coffee page. The Median Donation Amount for the calendar month wins! The Individual Task In order to achieve the desired vision, multiple contributors would be appreciated; as of 2024-08-06 it is just myself. + + + Strength in Data: Connecting to the Taskmaster Database + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! This article provides an overview of Trabajo de las Mesas, a pivotal database that will be central to this project. The article will also provide guidance on how to connect to the database from within R. Trabajo de las Mesas Database Trabajo de las Mesas (TdlM 1) provides a plethora of data associated with Taskmaster in a database format. + + + About Me + //localhost:4321/about/ + Mon, 08 Jul 2024 00:00:00 +0000 + //localhost:4321/about/ + My Professional Background I obtained a PhD in Statistics from the University of Warwick in 2013, my thesis title was &ldquo;Uncertainty in Changepoints in Time Series&rdquo; 1. I&rsquo;m delighted that Dr Little Alex Horne recently became associated with my alma mater through the Taskmaster Education scheme. I have 10 years of industry experience as a Research Scientist/Data Scientist at Amazon and Samsung, predominantly demand forecasting at scale for products. From this experience, I have some experience on running projects at scale, with rigor (automation, repeatability) and compromises that need to be made (whether it be technical, monetary, mental). + + + New Post on Archie + //localhost:4321/2024/07/new-post-on-archie/ + Sat, 06 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/new-post-on-archie/ + Intro This is my first post in the Archie template in hugo. Here&rsquo;s a random sample from the standard Normal distribution. rnorm(5) ## [1] -0.3637057 -0.4214060 0.6501004 -0.8329920 1.3021409 Here&rsquo;s an image of a duck. Did I create a html from this? + + + Resources + //localhost:4321/resources/ + Thu, 04 Jul 2024 00:00:00 +0000 + //localhost:4321/resources/ + Here are some of the resources I used as part of The Median Duck. (I will tabulate and automate this eventually). Taskmaster Related TaskMaster.Info Trabajo de las Mesas Website Related Feather Icons Statistics Related Misc Related + + + The Vision + //localhost:4321/vision/ + Thu, 04 Jul 2024 00:00:00 +0000 + //localhost:4321/vision/ + The Mission Statement To entertain and educate the general public of statistical and analytical concepts through data associated with the hit UK TV show “Taskmaster”. The Objective Using data from the UK hit TV show “Taskmaster”, The Median Duck aims to entertain and educate the general public of statistical and analytical concepts. Articles and analysis will be written for a non-technical audience predominantly. Types of analysis and content fall under the following umbrellas with some examples. + + + Hello R Markdown + //localhost:4321/2020/12/hello-r-markdown/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/2020/12/hello-r-markdown/ + R Markdown This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com. You can embed an R code chunk like this: summary(cars) ## speed dist ## Min. : 4.0 Min. : 2.00 ## 1st Qu.:12.0 1st Qu.: 26.00 ## Median :15.0 Median : 36.00 ## Mean :15.4 Mean : 42.98 ## 3rd Qu. + + + Telegram Bot for GitHub Actions + //localhost:4321/2020/04/telegram-bot-for-github-actions/ + Wed, 01 Apr 2020 00:00:00 +0000 + //localhost:4321/2020/04/telegram-bot-for-github-actions/ + Telegram Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API. GitHub Actions GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. + + + Primer: When You Have Too Much to Do + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + Wed, 01 Apr 2020 02:01:58 +0530 + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more. It all keeps piling up, and it can feel overwhelming. How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate? + + + Getting Started with Traveling Ultralight + //localhost:4321/2020/03/getting-started-with-traveling-ultralight/ + Wed, 18 Mar 2020 12:13:35 +0530 + //localhost:4321/2020/03/getting-started-with-traveling-ultralight/ + I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said. I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. + + + + //localhost:4321/archives/ + Tue, 28 May 2019 00:00:00 +0000 + //localhost:4321/archives/ + + + + How to test dark mode? + //localhost:4321/2018/03/how-to-test-dark-mode/ + Sun, 18 Mar 2018 12:13:38 +0530 + //localhost:4321/2018/03/how-to-test-dark-mode/ + Here is how you can setup dark mode for Ink and test on various OS like iOS, Android, macOS and Windows 10. + + + Typography + //localhost:4321/2018/03/typography/ + Sun, 18 Mar 2018 12:13:38 +0530 + //localhost:4321/2018/03/typography/ + Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. Heading 1 Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. + + + Hugo shortcodes + //localhost:4321/2018/03/hugo-shortcodes/ + Sun, 18 Mar 2018 12:13:36 +0530 + //localhost:4321/2018/03/hugo-shortcodes/ + Images Github Gist Youtube video Vimeo Instagram View this post on Instagram Callouts 💡 I guess this works + + + How I Learned to Stop Procrastinating, & Love Letting Go + //localhost:4321/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/ + Sun, 18 Mar 2018 12:13:32 +0530 + //localhost:4321/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/ + The end of procrastination is the art of letting go. I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done. Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. + + + Fearlessness: How to Stop Running from Space + //localhost:4321/2018/03/fearlessness-how-to-stop-running-from-space/ + Sun, 18 Mar 2018 12:13:30 +0530 + //localhost:4321/2018/03/fearlessness-how-to-stop-running-from-space/ + We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos. We are afraid of empty space in our lives. The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives. We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. + + + diff --git a/public/js/feather.min.js b/public/js/feather.min.js new file mode 100644 index 0000000..d229492 --- /dev/null +++ b/public/js/feather.min.js @@ -0,0 +1,13 @@ +!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.feather=n():e.feather=n()}("undefined"!=typeof self?self:this,function(){return function(e){var n={};function i(l){if(n[l])return n[l].exports;var t=n[l]={i:l,l:!1,exports:{}};return e[l].call(t.exports,t,t.exports,i),t.l=!0,t.exports}return i.m=e,i.c=n,i.d=function(e,n,l){i.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:l})},i.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},i.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(n,"a",n),n},i.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},i.p="",i(i.s=61)}([function(e,n,i){var l=i(20)("wks"),t=i(11),r=i(1).Symbol,o="function"==typeof r;(e.exports=function(e){return l[e]||(l[e]=o&&r[e]||(o?r:t)("Symbol."+e))}).store=l},function(e,n){var i=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=i)},function(e,n){var i=e.exports={version:"2.5.6"};"number"==typeof __e&&(__e=i)},function(e,n){var i={}.hasOwnProperty;e.exports=function(e,n){return i.call(e,n)}},function(e,n,i){e.exports=!i(27)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,n,i){var l=i(13);e.exports=function(e){if(!l(e))throw TypeError(e+" is not an object!");return e}},function(e,n,i){var l=i(5),t=i(56),r=i(55),o=Object.defineProperty;n.f=i(4)?Object.defineProperty:function(e,n,i){if(l(e),n=r(n,!0),l(i),t)try{return o(e,n,i)}catch(e){}if("get"in i||"set"in i)throw TypeError("Accessors not supported!");return"value"in i&&(e[n]=i.value),e}},function(e,n,i){var l=i(6),t=i(12);e.exports=i(4)?function(e,n,i){return l.f(e,n,t(1,i))}:function(e,n,i){return e[n]=i,e}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var l=o(i(35)),t=o(i(33)),r=o(i(32));function o(e){return e&&e.__esModule?e:{default:e}}n.default=Object.keys(t.default).map(function(e){return new l.default(e,t.default[e],r.default[e])}).reduce(function(e,n){return e[n.name]=n,e},{})},function(e,n,i){var l=i(20)("keys"),t=i(11);e.exports=function(e){return l[e]||(l[e]=t(e))}},function(e,n){e.exports={}},function(e,n){var i=0,l=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++i+l).toString(36))}},function(e,n){e.exports=function(e,n){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:n}}},function(e,n){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,n){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,n){var i=Math.ceil,l=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?l:i)(e)}},function(e,n,i){var l; +/*! + Copyright (c) 2016 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ +/*! + Copyright (c) 2016 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ +!function(){"use strict";var i=function(){function e(){}function n(e,n){for(var i=n.length,l=0;l0?t(l(e),9007199254740991):0}},function(e,n){var i={}.toString;e.exports=function(e){return i.call(e).slice(8,-1)}},function(e,n,i){var l=i(48),t=i(14);e.exports=function(e){return l(t(e))}},function(e,n,i){var l=i(54);e.exports=function(e,n,i){if(l(e),void 0===n)return e;switch(i){case 1:return function(i){return e.call(n,i)};case 2:return function(i,l){return e.call(n,i,l)};case 3:return function(i,l,t){return e.call(n,i,l,t)}}return function(){return e.apply(n,arguments)}}},function(e,n,i){var l=i(1),t=i(7),r=i(3),o=i(11)("src"),a=Function.toString,c=(""+a).split("toString");i(2).inspectSource=function(e){return a.call(e)},(e.exports=function(e,n,i,a){var y="function"==typeof i;y&&(r(i,"name")||t(i,"name",n)),e[n]!==i&&(y&&(r(i,o)||t(i,o,e[n]?""+e[n]:c.join(String(n)))),e===l?e[n]=i:a?e[n]?e[n]=i:t(e,n,i):(delete e[n],t(e,n,i)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[o]||a.call(this)})},function(e,n,i){var l=i(13),t=i(1).document,r=l(t)&&l(t.createElement);e.exports=function(e){return r?t.createElement(e):{}}},function(e,n){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,n,i){var l=i(1),t=i(2),r=i(7),o=i(25),a=i(24),c=function(e,n,i){var y,p,h,x,s=e&c.F,u=e&c.G,d=e&c.S,f=e&c.P,v=e&c.B,g=u?l:d?l[n]||(l[n]={}):(l[n]||{}).prototype,m=u?t:t[n]||(t[n]={}),M=m.prototype||(m.prototype={});for(y in u&&(i=n),i)h=((p=!s&&g&&void 0!==g[y])?g:i)[y],x=v&&p?a(h,l):f&&"function"==typeof h?a(Function.call,h):h,g&&o(g,y,h,e&c.U),m[y]!=h&&r(m,y,x),f&&M[y]!=h&&(M[y]=h)};l.core=t,c.F=1,c.G=2,c.S=4,c.P=8,c.B=16,c.W=32,c.U=64,c.R=128,e.exports=c},function(e,n){e.exports=!1},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var l=Object.assign||function(e){for(var n=1;n0&&void 0!==arguments[0]?arguments[0]:{};if("undefined"==typeof document)throw new Error("`feather.replace()` only works in a browser environment.");var n=document.querySelectorAll("[data-feather]");Array.from(n).forEach(function(n){return function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=function(e){return Array.from(e.attributes).reduce(function(e,n){return e[n.name]=n.value,e},{})}(e),o=i["data-feather"];delete i["data-feather"];var a=r.default[o].toSvg(l({},n,i,{class:(0,t.default)(n.class,i.class)})),c=(new DOMParser).parseFromString(a,"image/svg+xml").querySelector("svg");e.parentNode.replaceChild(c,e)}(n,e)})}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var l,t=i(8),r=(l=t)&&l.__esModule?l:{default:l};n.default=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(console.warn("feather.toSvg() is deprecated. Please use feather.icons[name].toSvg() instead."),!e)throw new Error("The required `key` (icon name) parameter is missing.");if(!r.default[e])throw new Error("No icon matching '"+e+"'. See the complete list of icons at https://feathericons.com");return r.default[e].toSvg(n)}},function(e){e.exports={activity:["pulse","health","action","motion"],airplay:["stream","cast","mirroring"],"alert-circle":["warning"],"alert-octagon":["warning"],"alert-triangle":["warning"],"at-sign":["mention"],award:["achievement","badge"],aperture:["camera","photo"],bell:["alarm","notification"],"bell-off":["alarm","notification","silent"],bluetooth:["wireless"],"book-open":["read"],book:["read","dictionary","booklet","magazine"],bookmark:["read","clip","marker","tag"],briefcase:["work","bag","baggage","folder"],clipboard:["copy"],clock:["time","watch","alarm"],"cloud-drizzle":["weather","shower"],"cloud-lightning":["weather","bolt"],"cloud-rain":["weather"],"cloud-snow":["weather","blizzard"],cloud:["weather"],codepen:["logo"],codesandbox:["logo"],coffee:["drink","cup","mug","tea","cafe","hot","beverage"],command:["keyboard","cmd"],compass:["navigation","safari","travel"],copy:["clone","duplicate"],"corner-down-left":["arrow"],"corner-down-right":["arrow"],"corner-left-down":["arrow"],"corner-left-up":["arrow"],"corner-right-down":["arrow"],"corner-right-up":["arrow"],"corner-up-left":["arrow"],"corner-up-right":["arrow"],"credit-card":["purchase","payment","cc"],crop:["photo","image"],crosshair:["aim","target"],database:["storage"],delete:["remove"],disc:["album","cd","dvd","music"],"dollar-sign":["currency","money","payment"],droplet:["water"],edit:["pencil","change"],"edit-2":["pencil","change"],"edit-3":["pencil","change"],eye:["view","watch"],"eye-off":["view","watch"],"external-link":["outbound"],facebook:["logo"],"fast-forward":["music"],figma:["logo","design","tool"],film:["movie","video"],"folder-minus":["directory"],"folder-plus":["directory"],folder:["directory"],frown:["emoji","face","bad","sad","emotion"],gift:["present","box","birthday","party"],"git-branch":["code","version control"],"git-commit":["code","version control"],"git-merge":["code","version control"],"git-pull-request":["code","version control"],github:["logo","version control"],gitlab:["logo","version control"],global:["world","browser","language","translate"],"hard-drive":["computer","server"],hash:["hashtag","number","pound"],headphones:["music","audio"],heart:["like","love"],"help-circle":["question mark"],hexagon:["shape","node.js","logo"],home:["house"],image:["picture"],inbox:["email"],instagram:["logo","camera"],key:["password","login","authentication"],"life-bouy":["help","life ring","support"],linkedin:["logo"],lock:["security","password"],"log-in":["sign in","arrow"],"log-out":["sign out","arrow"],mail:["email"],"map-pin":["location","navigation","travel","marker"],map:["location","navigation","travel"],maximize:["fullscreen"],"maximize-2":["fullscreen","arrows"],meh:["emoji","face","neutral","emotion"],menu:["bars","navigation","hamburger"],"message-circle":["comment","chat"],"message-square":["comment","chat"],"mic-off":["record"],mic:["record"],minimize:["exit fullscreen"],"minimize-2":["exit fullscreen","arrows"],monitor:["tv"],moon:["dark","night"],"more-horizontal":["ellipsis"],"more-vertical":["ellipsis"],"mouse-pointer":["arrow","cursor"],move:["arrows"],navigation:["location","travel"],"navigation-2":["location","travel"],octagon:["stop"],package:["box"],paperclip:["attachment"],pause:["music","stop"],"pause-circle":["music","stop"],"pen-tool":["vector","drawing"],play:["music","start"],"play-circle":["music","start"],plus:["add","new"],"plus-circle":["add","new"],"plus-square":["add","new"],pocket:["logo","save"],power:["on","off"],radio:["signal"],rewind:["music"],rss:["feed","subscribe"],save:["floppy disk"],search:["find","magnifier","magnifying glass"],send:["message","mail","paper airplane"],settings:["cog","edit","gear","preferences"],shield:["security"],"shield-off":["security"],"shopping-bag":["ecommerce","cart","purchase","store"],"shopping-cart":["ecommerce","cart","purchase","store"],shuffle:["music"],"skip-back":["music"],"skip-forward":["music"],slash:["ban","no"],sliders:["settings","controls"],smile:["emoji","face","happy","good","emotion"],speaker:["music"],star:["bookmark","favorite","like"],sun:["brightness","weather","light"],sunrise:["weather"],sunset:["weather"],tag:["label"],target:["bullseye"],terminal:["code","command line"],"thumbs-down":["dislike","bad"],"thumbs-up":["like","good"],"toggle-left":["on","off","switch"],"toggle-right":["on","off","switch"],trash:["garbage","delete","remove"],"trash-2":["garbage","delete","remove"],triangle:["delta"],truck:["delivery","van","shipping"],twitter:["logo"],umbrella:["rain","weather"],"video-off":["camera","movie","film"],video:["camera","movie","film"],voicemail:["phone"],volume:["music","sound","mute"],"volume-1":["music","sound"],"volume-2":["music","sound"],"volume-x":["music","sound","mute"],watch:["clock","time"],wind:["weather","air"],"x-circle":["cancel","close","delete","remove","times"],"x-octagon":["delete","stop","alert","warning","times"],"x-square":["cancel","close","delete","remove","times"],x:["cancel","close","delete","remove","times"],youtube:["logo","video","play"],"zap-off":["flash","camera","lightning"],zap:["flash","camera","lightning"]}},function(e){e.exports={activity:'',airplay:'',"alert-circle":'',"alert-octagon":'',"alert-triangle":'',"align-center":'',"align-justify":'',"align-left":'',"align-right":'',anchor:'',aperture:'',archive:'',"arrow-down-circle":'',"arrow-down-left":'',"arrow-down-right":'',"arrow-down":'',"arrow-left-circle":'',"arrow-left":'',"arrow-right-circle":'',"arrow-right":'',"arrow-up-circle":'',"arrow-up-left":'',"arrow-up-right":'',"arrow-up":'',"at-sign":'',award:'',"bar-chart-2":'',"bar-chart":'',"battery-charging":'',battery:'',"bell-off":'',bell:'',bluetooth:'',bold:'',"book-open":'',book:'',bookmark:'',box:'',briefcase:'',calendar:'',"camera-off":'',camera:'',cast:'',"check-circle":'',"check-square":'',check:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',"chevrons-down":'',"chevrons-left":'',"chevrons-right":'',"chevrons-up":'',chrome:'',circle:'',clipboard:'',clock:'',"cloud-drizzle":'',"cloud-lightning":'',"cloud-off":'',"cloud-rain":'',"cloud-snow":'',cloud:'',code:'',codepen:'',codesandbox:'',coffee:'',columns:'',command:'',compass:'',copy:'',"corner-down-left":'',"corner-down-right":'',"corner-left-down":'',"corner-left-up":'',"corner-right-down":'',"corner-right-up":'',"corner-up-left":'',"corner-up-right":'',cpu:'',"credit-card":'',crop:'',crosshair:'',database:'',delete:'',disc:'',"dollar-sign":'',"download-cloud":'',download:'',droplet:'',"edit-2":'',"edit-3":'',edit:'',"external-link":'',"eye-off":'',eye:'',facebook:'',"fast-forward":'',feather:'',figma:'',"file-minus":'',"file-plus":'',"file-text":'',file:'',film:'',filter:'',flag:'',"folder-minus":'',"folder-plus":'',folder:'',frown:'',gift:'',"git-branch":'',"git-commit":'',"git-merge":'',"git-pull-request":'',github:'',gitlab:'',globe:'',grid:'',"hard-drive":'',hash:'',headphones:'',heart:'',"help-circle":'',hexagon:'',home:'',image:'',inbox:'',info:'',instagram:'',italic:'',key:'',layers:'',layout:'',"life-buoy":'',"link-2":'',link:'',linkedin:'',list:'',loader:'',lock:'',"log-in":'',"log-out":'',mail:'',"map-pin":'',map:'',"maximize-2":'',maximize:'',meh:'',menu:'',"message-circle":'',"message-square":'',"mic-off":'',mic:'',"minimize-2":'',minimize:'',"minus-circle":'',"minus-square":'',minus:'',monitor:'',moon:'',"more-horizontal":'',"more-vertical":'',"mouse-pointer":'',move:'',music:'',"navigation-2":'',navigation:'',octagon:'',package:'',paperclip:'',"pause-circle":'',pause:'',"pen-tool":'',percent:'',"phone-call":'',"phone-forwarded":'',"phone-incoming":'',"phone-missed":'',"phone-off":'',"phone-outgoing":'',phone:'',"pie-chart":'',"play-circle":'',play:'',"plus-circle":'',"plus-square":'',plus:'',pocket:'',power:'',printer:'',radio:'',"refresh-ccw":'',"refresh-cw":'',repeat:'',rewind:'',"rotate-ccw":'',"rotate-cw":'',rss:'',save:'',scissors:'',search:'',send:'',server:'',settings:'',"share-2":'',share:'',"shield-off":'',shield:'',"shopping-bag":'',"shopping-cart":'',shuffle:'',sidebar:'',"skip-back":'',"skip-forward":'',slack:'',slash:'',sliders:'',smartphone:'',smile:'',speaker:'',square:'',star:'',"stop-circle":'',sun:'',sunrise:'',sunset:'',tablet:'',tag:'',target:'',terminal:'',thermometer:'',"thumbs-down":'',"thumbs-up":'',"toggle-left":'',"toggle-right":'',"trash-2":'',trash:'',trello:'',"trending-down":'',"trending-up":'',triangle:'',truck:'',tv:'',twitter:'',type:'',umbrella:'',underline:'',unlock:'',"upload-cloud":'',upload:'',"user-check":'',"user-minus":'',"user-plus":'',"user-x":'',user:'',users:'',"video-off":'',video:'',voicemail:'',"volume-1":'',"volume-2":'',"volume-x":'',volume:'',watch:'',"wifi-off":'',wifi:'',wind:'',"x-circle":'',"x-octagon":'',"x-square":'',x:'',youtube:'',"zap-off":'',zap:'',"zoom-in":'',"zoom-out":''}},function(e){e.exports={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var l=Object.assign||function(e){for(var n=1;n2&&void 0!==arguments[2]?arguments[2]:[];!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,e),this.name=n,this.contents=i,this.tags=t,this.attrs=l({},o.default,{class:"feather feather-"+n})}return t(e,[{key:"toSvg",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return""+this.contents+""}},{key:"toString",value:function(){return this.contents}}]),e}();n.default=c},function(e,n,i){"use strict";var l=o(i(8)),t=o(i(31)),r=o(i(30));function o(e){return e&&e.__esModule?e:{default:e}}e.exports={icons:l.default,toSvg:t.default,replace:r.default}},function(e,n,i){var l=i(0)("iterator"),t=!1;try{var r=[7][l]();r.return=function(){t=!0},Array.from(r,function(){throw 2})}catch(e){}e.exports=function(e,n){if(!n&&!t)return!1;var i=!1;try{var r=[7],o=r[l]();o.next=function(){return{done:i=!0}},r[l]=function(){return o},e(r)}catch(e){}return i}},function(e,n,i){var l=i(22),t=i(0)("toStringTag"),r="Arguments"==l(function(){return arguments}());e.exports=function(e){var n,i,o;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(i=function(e,n){try{return e[n]}catch(e){}}(n=Object(e),t))?i:r?l(n):"Object"==(o=l(n))&&"function"==typeof n.callee?"Arguments":o}},function(e,n,i){var l=i(38),t=i(0)("iterator"),r=i(10);e.exports=i(2).getIteratorMethod=function(e){if(void 0!=e)return e[t]||e["@@iterator"]||r[l(e)]}},function(e,n,i){"use strict";var l=i(6),t=i(12);e.exports=function(e,n,i){n in e?l.f(e,n,t(0,i)):e[n]=i}},function(e,n,i){var l=i(10),t=i(0)("iterator"),r=Array.prototype;e.exports=function(e){return void 0!==e&&(l.Array===e||r[t]===e)}},function(e,n,i){var l=i(5);e.exports=function(e,n,i,t){try{return t?n(l(i)[0],i[1]):n(i)}catch(n){var r=e.return;throw void 0!==r&&l(r.call(e)),n}}},function(e,n,i){"use strict";var l=i(24),t=i(28),r=i(17),o=i(42),a=i(41),c=i(21),y=i(40),p=i(39);t(t.S+t.F*!i(37)(function(e){Array.from(e)}),"Array",{from:function(e){var n,i,t,h,x=r(e),s="function"==typeof this?this:Array,u=arguments.length,d=u>1?arguments[1]:void 0,f=void 0!==d,v=0,g=p(x);if(f&&(d=l(d,u>2?arguments[2]:void 0,2)),void 0==g||s==Array&&a(g))for(i=new s(n=c(x.length));n>v;v++)y(i,v,f?d(x[v],v):x[v]);else for(h=g.call(x),i=new s;!(t=h.next()).done;v++)y(i,v,f?o(h,d,[t.value,v],!0):t.value);return i.length=v,i}})},function(e,n,i){var l=i(3),t=i(17),r=i(9)("IE_PROTO"),o=Object.prototype;e.exports=Object.getPrototypeOf||function(e){return e=t(e),l(e,r)?e[r]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?o:null}},function(e,n,i){var l=i(1).document;e.exports=l&&l.documentElement},function(e,n,i){var l=i(15),t=Math.max,r=Math.min;e.exports=function(e,n){return(e=l(e))<0?t(e+n,0):r(e,n)}},function(e,n,i){var l=i(23),t=i(21),r=i(46);e.exports=function(e){return function(n,i,o){var a,c=l(n),y=t(c.length),p=r(o,y);if(e&&i!=i){for(;y>p;)if((a=c[p++])!=a)return!0}else for(;y>p;p++)if((e||p in c)&&c[p]===i)return e||p||0;return!e&&-1}}},function(e,n,i){var l=i(22);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==l(e)?e.split(""):Object(e)}},function(e,n,i){var l=i(3),t=i(23),r=i(47)(!1),o=i(9)("IE_PROTO");e.exports=function(e,n){var i,a=t(e),c=0,y=[];for(i in a)i!=o&&l(a,i)&&y.push(i);for(;n.length>c;)l(a,i=n[c++])&&(~r(y,i)||y.push(i));return y}},function(e,n,i){var l=i(49),t=i(19);e.exports=Object.keys||function(e){return l(e,t)}},function(e,n,i){var l=i(6),t=i(5),r=i(50);e.exports=i(4)?Object.defineProperties:function(e,n){t(e);for(var i,o=r(n),a=o.length,c=0;a>c;)l.f(e,i=o[c++],n[i]);return e}},function(e,n,i){var l=i(5),t=i(51),r=i(19),o=i(9)("IE_PROTO"),a=function(){},c=function(){var e,n=i(26)("iframe"),l=r.length;for(n.style.display="none",i(45).appendChild(n),n.src="javascript:",(e=n.contentWindow.document).open(),e.write(" + + Fearlessness: How to Stop Running from Space - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Fearlessness: How to Stop Running from Space

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos.

+

We are afraid of empty space in our lives.

+

The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives.

+

We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. We try to fill every second with activity, with something useful, as if silence and space are not valuable.

+

But what are we afraid of?

+

And who would we be if we didn’t have that fear?

+

We’re afraid of space and stillness and silence because it highlights the uncertainty, instability, groundlessness, insecurity, shakiness that lie underneath every second of our lives. We’re afraid of having to face this instability and uncertainty, of having to feel the fear of it.

+

Without the fear of all of the uncertainty that is highlighted by space … we become free.

+

I know in my life, when I allow myself to have stillness, silence, solitude, simplicity and space … it leaves room to face whatever is coming up for me. It gives me room to fully feel any feelings that I’ve been avoiding. It allows me to be more honest with myself, instead of using distractions and busyness to cover up what I don’t want to see.

+

And in the end, I develop trust that the space is not something to be feared, but rather something to be treasured. A gift, filled with learning and not knowing and shakiness and beauty.

+

You might try allowing more space to be in your day, without filling it:

+
    +
  • Take some time between tasks for stillness.
  • +
  • Sit out in nature, in silence, without technology.
  • +
  • When you notice yourself reaching for your phone, pause. See if you can just be still, just savor some space.
  • +
  • When you feel uncertainty or instability in your life (hint: it’s always there), let yourself feel it. Be present with it, without needing to run or avoid.
  • +
  • When you feel fear, be open-hearted with it and allow yourself fully feel it, being friendly with it. Your relationship with fear will change if you become friendly with it.
  • +
  • Do less, and trust that things won’t fall apart. Or if they do fall apart, you can be present with that instability.
  • +
  • When you’re in line, driving, eating, walking, exercising … see if you can do those things in silence, without technology, without needing to do something “useful.” Find the value in these spaces.
  • +
  • Notice who you are without the fear of space.
  • +
+

Savor these spaces, their deliciousness. Savor the groundlessness, as something filled with freedom if we learn not to fear it. Be present with the fear and uncertainty, as good friends not as enemies.

+

Let your heart be open raw tender and vulnerable, and your mind embracing the spaciousness of the vast blue sky of open awareness.

+ +
+ + +
+
+ +
+ + diff --git a/public/keywords/getting-started-with-traveling-ultralight/index.html b/public/keywords/getting-started-with-traveling-ultralight/index.html new file mode 100644 index 0000000..9eb1685 --- /dev/null +++ b/public/keywords/getting-started-with-traveling-ultralight/index.html @@ -0,0 +1,116 @@ + + + + Getting Started with Traveling Ultralight - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Getting Started with Traveling Ultralight

+
Posted on 2020-03-18 DRAFT
+
+ + +
+

I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said.

+

I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. But then I remembered that I’m far from normal in this way.

+

I gave him a tip for getting started, and I recommend it for all of you, who want to travel light — or ultralight, as I call it, because for many people traveling light is taking a carry-on roller luggage. For me, having those roller bags is lugging too much, because you can run up stairs with it with ease, or carry it all over a city without worrying about stowing away your luggage somewhere first. It’s so much easier to travel ultralight.

+

Here’s the tip I gave him to get started: start by getting a small backpack (less than 20 liters) and then just travel with what fits in that.

+

That’s how to start. But you’ll probably want some guidance on what to put into the bag, and how to travel with so little. Here’s some guidance to get started:

+
    +
  • I travel with a lightweight laptop (Macbook Air), a few clothes, my phone, earbuds and some charging cords, toiletries, and almost nothing else. A lightweight windbreaker for wind and light rain (Patagonia Houdini). An eye mask and ear plugs. A collapsible water bottle. My passport. That’s about it. No extra shoes. No books. No suit. No travel pillow. No extra camera other than my phone. I’m not sure what else everyone else brings, but none of that.
  • +
  • I bring clothes that I can wash in the sink or shower and that will dry overnight. Lightweight stuff that I can layer. Often they’re workout-style clothes or things from companies like Outlier or Patagonia that travel well. I don’t bring enough underwear or socks for every day of the trip, because I wash them every couple of days. I only bring one or two extra T-shirts, generally wearing the same two shirts the whole trip, even if it’s a month long. No one has ever once cared what I wear when I’m traveling.
  • +
  • I bring minimal toiletries: a small shaver for my head, razor, toothbrush, floss small tubes of toothpaste and shaving cream, deodorant, nail clippers, ibuprofen.
  • +
  • For cold places, I have thermal underwear and a couple long-sleeve layers (generally all Patagonia capilene stuff), and a beanie. I don’t usually go to places where it’s snowing (I don’t know why, maybe snow isn’t my thing), so I don’t have clothes to deal with that weather.
  • +
  • For warm places, I will bring flip flops and swim trunks, and leave most of the colder layers behind.
  • +
+

That’s enough for a monthlong trip, which I’ve done multiple times with this kind of setup. For a shorter trip of a few days, I might bring even less.

+

I really love traveling this way, and am more than willing to sacrifice bringing extra things for the luxury of traveling lightweight.

+

By the way, you don’t need much more than this kind of setup even in everyday life.

+

For more info on this, check out my Ultralight ebook, and my friend Tynan has a great book called Forever Nomad.

+ +
+ + +
+
+ +
+ + diff --git a/public/keywords/hello-r-markdown/index.Rmd b/public/keywords/hello-r-markdown/index.Rmd new file mode 100644 index 0000000..8768d78 --- /dev/null +++ b/public/keywords/hello-r-markdown/index.Rmd @@ -0,0 +1,38 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(collapse = TRUE) +``` + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + +```{r cars} +summary(cars) +fit <- lm(dist ~ speed, data = cars) +fit +``` + +# Including Plots + +You can also embed plots. See Figure \@ref(fig:pie) for example: + +```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE} +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` diff --git a/public/keywords/hello-r-markdown/index.html b/public/keywords/hello-r-markdown/index.html new file mode 100644 index 0000000..cbc886a --- /dev/null +++ b/public/keywords/hello-r-markdown/index.html @@ -0,0 +1,151 @@ + + + + Hello R Markdown - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Hello R Markdown

+
Posted on 2020-12-01 DRAFT
+
+ + +
+

R Markdown

+

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

+

You can embed an R code chunk like this:

+
summary(cars)
+##      speed           dist       
+##  Min.   : 4.0   Min.   :  2.00  
+##  1st Qu.:12.0   1st Qu.: 26.00  
+##  Median :15.0   Median : 36.00  
+##  Mean   :15.4   Mean   : 42.98  
+##  3rd Qu.:19.0   3rd Qu.: 56.00  
+##  Max.   :25.0   Max.   :120.00
+fit <- lm(dist ~ speed, data = cars)
+fit
+## 
+## Call:
+## lm(formula = dist ~ speed, data = cars)
+## 
+## Coefficients:
+## (Intercept)        speed  
+##     -17.579        3.932
+

Including Plots

+

You can also embed plots. See Figure 1 for example:

+
par(mar = c(0, 1, 0, 1))
+pie(
+  c(280, 60, 20),
+  c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
+  col = c('#0292D8', '#F7EA39', '#C4B632'),
+  init.angle = -50, border = NA
+)
+
+ +
+ + +
+
+ +
+ + diff --git a/public/keywords/hello-r-markdown/index_files/figure-html/pie-1.png b/public/keywords/hello-r-markdown/index_files/figure-html/pie-1.png new file mode 100644 index 0000000..eef072f Binary files /dev/null and b/public/keywords/hello-r-markdown/index_files/figure-html/pie-1.png differ diff --git a/public/keywords/how-i-learned-to-stop-procrastinating-love-letting-go/index.html b/public/keywords/how-i-learned-to-stop-procrastinating-love-letting-go/index.html new file mode 100644 index 0000000..5d9c5b4 --- /dev/null +++ b/public/keywords/how-i-learned-to-stop-procrastinating-love-letting-go/index.html @@ -0,0 +1,127 @@ + + + + How I Learned to Stop Procrastinating, & Love Letting Go - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

How I Learned to Stop Procrastinating, & Love Letting Go

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

The end of procrastination is the art of letting go.

+

I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done.

+

Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. It stressed me out. My work was less-than-desirable when I did it last minute. Slowly, I started to realize that procrastination wasn’t doing me any favors. In fact, it was causing me a lot of grief.

+

But I couldn’t quit. I tried a lot of things. I tried time boxing and goal setting and accountability and the Pomodoro Technique and Getting Things Done. All are great methods, but they only last so long. Nothing really worked over the long term.

+

That’s because I wasn’t getting to the root problem.

+

I hadn’t figured out the skill that would save me from the procrastination.

+

Until I learned about letting go.

+

Letting go first came to me when I was quitting smoking. I had to let go of the “need” to smoke, the use of my crutch of cigarettes to deal with stress and problems.

+

Then I learned I needed to let go of other false needs that were causing me problems: sugar, junk food, meat, shopping, beer, possessions. I’m not saying I can never do these things again once I let go of these needs, but I let go of the idea that they’re really necessary. I let go of an unhealthy attachment to them.

+

Then I learned that distractions and the false need to check my email and news and other things online … were causing me problems. They were causing my procrastination.

+

So I learned to let go of those too.

+

Here’s the process I used to let go of the distractions and false needs that cause procrastination:

+

I paid attention to the pain they cause me, later, instead of only the temporary comfort/pleasure they gave me right away. +I thought about the person I want to be, the life I want to live. I set my intentions to do the good work I think I should do. +I watched my urges to check things, to go to the comfort of distractions. I saw that I wanted to escape discomfort of something hard, and go to the comfort of something familiar and easy. +I realized I didn’t need that comfort. I could be in discomfort and nothing bad would happen. In fact, the best things happen when I’m in discomfort. +And then I smile, and breathe, and let go.

+

And one step at a time, become the person I want to be.

+ +
+ + +
+
+ +
+ + diff --git a/public/keywords/how-to-test-dark-mode/index.html b/public/keywords/how-to-test-dark-mode/index.html new file mode 100644 index 0000000..a5ba338 --- /dev/null +++ b/public/keywords/how-to-test-dark-mode/index.html @@ -0,0 +1,112 @@ + + + + How to test dark mode? - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

How to test dark mode?

+
Posted on 2018-03-18 DRAFT
+
+ +
+ tl;dr: + Wubba lubba dub dub +
+ +
+

You can set dark mode as default by setting params.mode to dark in config.toml or set it to auto which will detect based on your OS and switch to dark mode. For more details refer documentation

+

Here is how you can switch based on your OS

+ + +
+ + +
+
+ +
+ + diff --git a/public/keywords/hugo-shortcodes/index.html b/public/keywords/hugo-shortcodes/index.html new file mode 100644 index 0000000..dd00454 --- /dev/null +++ b/public/keywords/hugo-shortcodes/index.html @@ -0,0 +1,355 @@ + + + + Hugo shortcodes - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+ +
+ +
+ + diff --git a/public/keywords/new-post-on-archie/index.Rmarkdown b/public/keywords/new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..e9196ed --- /dev/null +++ b/public/keywords/new-post-on-archie/index.Rmarkdown @@ -0,0 +1,25 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? \ No newline at end of file diff --git a/public/keywords/new-post-on-archie/index.html b/public/keywords/new-post-on-archie/index.html new file mode 100644 index 0000000..8d75747 --- /dev/null +++ b/public/keywords/new-post-on-archie/index.html @@ -0,0 +1,126 @@ + + + + New Post on Archie - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

New Post on Archie

+
Posted on 2024-07-06
+
+ + +
+

Intro

+

This is my first post in the Archie template in hugo.

+

Here’s a random sample from the standard Normal distribution.

+
rnorm(5)
+
## [1] -0.3637057 -0.4214060  0.6501004 -0.8329920  1.3021409
+

Here’s an image of a duck.

+

+

Did I create a html from this?

+ +
+ + +
+
+ +
+ + diff --git a/public/keywords/primer-when-you-have-too-much-to-do/index.html b/public/keywords/primer-when-you-have-too-much-to-do/index.html new file mode 100644 index 0000000..2b8ed87 --- /dev/null +++ b/public/keywords/primer-when-you-have-too-much-to-do/index.html @@ -0,0 +1,146 @@ + + + + Primer: When You Have Too Much to Do - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Primer: When You Have Too Much to Do

+
Posted on 2020-04-01 DRAFT
+
+ + +
+

You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more.

+

It all keeps piling up, and it can feel overwhelming.

+

How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate?

+

In this primer, I’ll look at some key strategies and tactics for taking on an overloaded life with an open heart, lots of energy, and a smile on your face.

+

The First Step: Triage

+

Whether you’re just starting your day, or you’re in the middle of the chaos and just need to find some sanity … the first step is to get into triage mode.

+

Triage, as you probably know, is sorting through the chaos to prioritize: what needs to be done now, what needs to be done today, what needs to be done this week, and what can wait? You’re looking at urgency, but also what’s meaningful and important.

+

Here’s what you might do:

+
    +
  • Pick out the things that need to be done today. Start a Short List for things you’re going to do today. That might be important tasks for big projects, urgent tasks that could result in damage if you don’t act, smaller admin tasks that you really should take care of today, and responding to important messages. I would recommend being ruthless and cutting out as much as you can, having just 5 things on your plate if that’s at all possible. Not everything needs to be done today, and not every email needs to be responded to.
  • +
  • Push some things to tomorrow and the rest of the week. If you have deadlines that can be pushed back (or renegotiated), do that. Spread the work out over the week, even into next week. What needs to be done tomorrow? What can wait a day or two longer?
  • +
  • Eliminate what you can. That might mean just not replying to some messages that aren’t that important and don’t really require a reply. It might mean telling some people that you can’t take on this project after all, or that you need to get out of the commitment that you said you’d do. Yes, this is uncomfortable. For now, just put them on a list called, “To Not Do,” and plan to figure out how to get out of them later.
  • +
+

OK, you have some breathing room and a manageable list now! Let’s shrink that down even further and just pick one thing.

+

Next: Focus on One Thing

+

With a lot on your plate, it’s hard to pick one thing to focus on. But that’s exactly what I’m going to ask you to do.

+

Pick one thing, and give it your focus. Yes, there are a lot of other things you can focus on. Yes, they’re stressing you out and making it hard to focus. But think about it this way: if you allow it all to be in your head all the time, that will always be your mode of being. You’ll always be thinking about everything, stressing out about it all, with a frazzled mind … unless you start shifting.

+

The shift:

+
    +
  • Pick something to focus on. Look at the triaged list from the first section … if you have 5-6 things on this Short List, you can assess whether there’s any super urgent, time-sensitive things you need to take care of. If there are, pick one of them. If not, pick the most important one — probably the one you have been putting off doing.
  • +
  • Clear everything else away. Just for a little bit. Close all browser tabs, turn off notifications, close open applications, put your phone away.
  • +
  • Put that one task before you, and allow yourself to be with it completely. Pour yourself into it. Think of it as a practice, of letting go (of everything else), of focus, of radical simplicity.
  • +
+

When you’re done (or after 15-20 minutes have gone by at least), you can switch to something else. But don’t allow yourself to switch until then.

+

By closing off all exits, by choosing one thing, by giving yourself completely to that thing … you’re now in a different mode that isn’t so stressful or spread thin. You’ve started a shift that will lead to focus and sanity.

+

Third: Schedule Time to Simplify

+

Remember the To Not Do list above? Schedule some time this week to start reducing your projects, saying no to people, getting out of commitments, crossing stuff off your task list … so that you can have some sanity back.

+

There are lots of little things that you’ve said “yes” to that you probably shouldn’t have. That’s why you’re overloaded. Protect your more important work, and your time off, and your peace of mind, by saying “no” to things that aren’t as important.

+

Schedule the time to simplify — you don’t have to do it today, but sometime soon — and you can then not have to worry about the things on your To Not Do list until then.

+

Fourth: Practice Mindful Focus

+

Go through the rest of the day with an attitude of “mindful focus.” That means that you are doing one thing at a time, being as present as you can, switching as little as you can.

+

Think of it as a settling of the mind. A new mode of being. A mindfulness practice (which means you won’t be perfect at it).

+

As you practice mindful focus, you’ll learn to practice doing things with an open heart, with curiosity and gratitude, and even joy. Try these one at a time as you get to do each task on your Short List.

+

You’ll find that you’re not so overloaded, but that each task is just perfect for that moment. And that’s a completely new relationship with the work that you do, and a new relationship with life.

+ +
+ + +
+
+ +
+ + diff --git a/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db b/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db differ diff --git a/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..9dca299 --- /dev/null +++ b/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,179 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +categories: ["Getting Started", "Introduction", "Beginner", "Setup"] +tags: + - Introduction + - Setup + - Beginner + - Getting Started +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 1 +--- + +```{r setup, include=FALSE, echo = FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../") +``` + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +# Introduction and Objective + +This article provides an overview of *Trabajo de las Mesas*, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC + +The article will also provide guidance on how to connect to the database from within . + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM^\[Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.\]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +## Data Quality + +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. . + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + +## Why This Datasource? + +As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + +However, for the purposes of this project, being able to query from database has several advantages. This includes: + +- Quality: Data being in a structured tabular format which often leads to better data quality +- Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc) +- Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + +## Potential Areas to Explore in the Future + +- Greater understanding of how the data is being collected. + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- Generate a data dictionary page + - What tables are available, samples of the data, what the table pertains to, and key columns. +- A dashboard on data quality. + - A highlevel overview of the quality and how recent the data is. + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download} +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +repo_root_dir <- getwd() +db_file_name <- "taskmaster.db" +data_dir <- "Data" + +db_data_location <- file.path(repo_root_dir, data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(repo_root_dir, data_dir))){ + dir.create(file.path(repo_root_dir, data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` + +## Connecting to the `.db` file + +Now that the database file has been successfully downloaded, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + +## Querying the Database + +Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation + +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts +LEFT JOIN people tp +ON ts.id = tp.series +AND ts.champion = tp.id +WHERE ts.special <> 1 +" + +results <- dbGetQuery(tm_db, query) +results +``` + +The results of this query already indicate interesting insights, namely that 204 days (approximately `r round(204/7)` weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag? + +# Times Up! + +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/index.html b/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/index.html new file mode 100644 index 0000000..0df2dd9 --- /dev/null +++ b/public/keywords/strength-in-data-connecting-to-the-taskmaster-database/index.html @@ -0,0 +1,305 @@ + + + + Strength in Data: Connecting to the Taskmaster Database - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Strength in Data: Connecting to the Taskmaster Database

+
Posted on 2024-07-10
+
+ + +
+

Your Task

+
+

Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now!

+
+

Introduction and Objective

+

This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC

+

The article will also provide guidance on how to connect to the database from within .

+

Trabajo de las Mesas Database

+

Trabajo de las Mesas (TdlM^[Taskmaster fanatics will know that this is in reference to the hint in S2E5’s task Build a bridge for the potato., which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant.

+

The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project.

+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource. .

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+

Why This Datasource?

+

As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+

Potential Areas to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
    +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
    +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
    +
  • +
+

Connecting to the Database from R

+

Downloading the .db file

+

It is possible to view and query these the numerous tables in TdlM from the website itself. However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as R or python, naturally leads to repeatablility and reproduceability.

+

I opting choosing to choose R for this project due to my familarity with it, and the high level visualisations and modelling that can be employed.

+

The tables displayed on the website are powered from the following database file which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist.

+
# URL where Database file resides. We will download from here.
+db_url <- "https://tdlm.fly.dev/taskmaster.db"
+
+# Where the data will be stored locally
+repo_root_dir <- getwd()
+db_file_name <- "taskmaster.db"
+data_dir <- "Data"
+
+db_data_location <- file.path(repo_root_dir, data_dir, db_file_name)
+
+
+# Create Data Directory if does not exist
+if(!file.exists(file.path(repo_root_dir, data_dir))){
+    dir.create(file.path(repo_root_dir, data_dir))
+}
+
+# Download file specified by URL, save in the local destination.
+if(!file.exists(db_data_location)){
+    download.file(url = db_url, destfile = db_data_location, mode = "wb")
+}
+

Connecting to the .db file

+

Now that the database file has been successfully downloaded, we can start to connect to it from R directory. The DBI package will be employed to establish this connection.

+
package_name <- "RSQLite"
+
+if(!require(package_name, character.only = TRUE)){
+    install.packages(package_name, character.only = TRUE)
+} else{
+    library(package_name, character.only = TRUE)    
+}
+
## Loading required package: RSQLite
+
# Driver used to establish database connection
+sqlite_driver <- dbDriver("SQLite")
+
+# Making the connection 
+tm_db <- dbConnect(sqlite_driver, dbname = db_data_location)
+

If successful, we should be able to list all the tables included in the database.

+
# List all tables that are available in the database
+dbListTables(tm_db)
+
##  [1] "attempts"           "discrepancies"      "episode_scores"    
+##  [4] "episodes"           "intros"             "measurements"      
+##  [7] "normalized_scores"  "objectives"         "people"            
+## [10] "podcast"            "profanity"          "series"            
+## [13] "series_scores"      "special_locations"  "task_briefs"       
+## [16] "task_readers"       "task_winners"       "tasks"             
+## [19] "tasks_by_objective" "team_tasks"         "teams"             
+## [22] "title_coiners"      "title_stats"
+

Querying the Database

+

Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from R to access the data. For example:

+

A Basic SELECT query

+
# A Basic Select query  on the series table.
+query <- "SELECT * FROM series LIMIT 10"
+
+dbGetQuery(tm_db, query)
+
##    id     name episodes champion  air_start    air_end studio_start studio_end
+## 1  -7  CoC III        0       NA 2024-??-?? 2024-??-??   2023-11-28 2023-11-28
+## 2  -6 NYT 2024        0       NA 2024-01-01 2024-01-01   2023-11-27 2023-11-27
+## 3  -5 NYT 2023        1       96 2023-01-01 2023-01-01   2022-11-22 2022-11-22
+## 4  -4   CoC II        1       87 2022-06-23 2022-06-23   2021-09-15 2021-09-15
+## 5  -3 NYT 2022        1       73 2022-01-01 2022-01-01         <NA>       <NA>
+## 6  -2 NYT 2021        1       62 2021-01-01 2021-01-01         <NA>       <NA>
+## 7  -1      CoC        2       29 2017-12-13 2017-12-20   2017-11-20 2017-11-20
+## 8   1 Series 1        6        4 2015-07-28 2015-09-01   2015-03-23 2015-03-25
+## 9   2 Series 2        5       11 2016-06-21 2016-07-19         <NA>       <NA>
+## 10  3 Series 3        5       16 2016-10-04 2016-11-01         <NA>       <NA>
+##    points tasks special TMI
+## 1      NA    NA       1  88
+## 2      NA    NA       1  87
+## 3      76     5       1  66
+## 4      66     5       1  46
+## 5      68     5       1  47
+## 6      62     5       1  12
+## 7     164    10       1   6
+## 8     436    32       0   1
+## 9     417    28       0   2
+## 10    386    27       0   3
+

Advanced query

+

A more involved query involving JOIN and date manipulation

+
# A join, and data manipulation
+query <- "SELECT ts.name,
+ts.special as special_flag,
+tp.name as champion_name,
+tp.seat as chamption_seat,
+DATE(ts.studio_end) as studio_end, 
+DATE(ts.air_start) as air_start, 
+JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days
+FROM series ts
+LEFT JOIN people tp
+ON ts.id = tp.series
+AND ts.champion = tp.id
+WHERE ts.special <> 1
+"
+
+results <- dbGetQuery(tm_db, query)
+results
+
##         name special_flag    champion_name chamption_seat studio_end  air_start
+## 1   Series 1            0  Josh Widdicombe              2 2015-03-25 2015-07-28
+## 2   Series 2            0   Katherine Ryan              4       <NA> 2016-06-21
+## 3   Series 3            0      Rob Beckett              4       <NA> 2016-10-04
+## 4   Series 4            0    Noel Fielding              5       <NA> 2017-04-25
+## 5   Series 5            0     Bob Mortimer              2 2017-07-06 2017-09-13
+## 6   Series 6            0     Liza Tarbuck              3 2018-03-28 2018-05-02
+## 7   Series 7            0   Kerry Godliman              3 2018-07-25 2018-09-05
+## 8   Series 8            0      Lou Sanders              3 2019-03-27 2019-05-08
+## 9   Series 9            0        Ed Gamble              2 2019-07-24 2019-09-04
+## 10 Series 10            0  Richard Herring              5 2020-07-29 2020-10-15
+## 11 Series 11            0    Sarah Kendall              5       <NA> 2021-03-18
+## 12 Series 12            0 Morgana Robinson              4       <NA> 2021-09-23
+## 13 Series 13            0     Sophie Duker              5 2021-09-22 2022-04-14
+## 14 Series 14            0    Dara Ó Briain              1 2022-05-05 2022-09-29
+## 15 Series 15            0       Mae Martin              5 2022-09-28 2023-03-30
+## 16 Series 16            0     Sam Campbell              3 2023-05-12 2023-09-21
+##    broadcast_lag_days
+## 1                 125
+## 2                  NA
+## 3                  NA
+## 4                  NA
+## 5                  69
+## 6                  35
+## 7                  42
+## 8                  42
+## 9                  42
+## 10                 78
+## 11                 NA
+## 12                 NA
+## 13                204
+## 14                147
+## 15                183
+## 16                132
+

The results of this query already indicate interesting insights, namely that 204 days (approximately 29 weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag?

+

Times Up!

+

And that concludes this task! Hopefully you’ve been able to connect to the TdlM database directly through R and potentially inspired to start performing your own analysis.

+ +
+ + +
+
+ +
+ + diff --git a/public/keywords/telegram-bot-for-github-actions/index.html b/public/keywords/telegram-bot-for-github-actions/index.html new file mode 100644 index 0000000..0f5cffd --- /dev/null +++ b/public/keywords/telegram-bot-for-github-actions/index.html @@ -0,0 +1,439 @@ + + + + Telegram Bot for GitHub Actions - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Telegram Bot for GitHub Actions

+
Posted on 2020-04-01 DRAFT
+
+ +
+ tl;dr: + Making GitHub Actions with Js Code +
+ +
+

Telegram

+

Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API.

+

GitHub Actions

+

GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. You can build, test and deploy your code with GitHub Actions. All these actions are called workflows and workflows differ in the job they’re doing. These maybe test workflows, build ones or deployment ones. You can find all the actions on GitHub in the marketplace

+

Building the Bot

+

Prerequisites

+
    +
  • Basic JavaScript Knowledge
  • +
  • Basic GitHub Knowledge
  • +
  • Telegram Account
  • +
+
+

There are templates for building actions. Here we’re gonna start from scratch

+
+

Environment Setup

+
    +
  • Node, You can download node from their website
  • +
  • NPM comes with node, so you don’t have to worry about it.
  • +
  • Initialize the Project
  • +
+
$ git init ## initialize a new git repository for version management
+---
+$ npm init
+
    +
  • dotenv, Dotenv can be downloaded via
  • +
+
$ npm i dotenv
+---
+$ yarn add dotenv
+
    +
  • node-telegram-bot-api, node-telegram-bot-api is a simple wrapper for building telegram bots. You can download it via
  • +
+
$ npm i node-telegram-bot-api
+---
+$ yarn add node-telegram-bot-api
+
    +
  • @zeit/ncc, NCC is a Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, GCC-style. It’s a dev dependency and can be downloaded
  • +
+
yarn add --dev @zeit/ncc
+---
+npm i -D @zeit/ncc
+

Folder Structure

+

The dist folder will be automatically created. action.yml will be made

+
.
+├── dist
+│   └── index.js
+├── index.js
+├── action.yml
+├── README.md
+└── package.json
+
    +
  • index.js is the file we’re defining the bot
  • +
  • action.yml is the file we’ll define the action and it’s behaviours
  • +
+

Making the Bot

+

We need to get an API bot token from telegram. For that Go to Telegram and Search for Botfather. It’s a bot. + +Create a new bot with the /newbot command and get the API key. We’ll need that, also talk to jsondump bot and get your chat id. The output may be like this, so

+
{
+  "update_id": 143943779,
+  "message": {
+    "message_id": 181575,
+    "from": {
+      "id": 123456 // this is what we need
+      "is_bot": false,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "language_code": "en"
+    },
+    "chat": {
+      "id": 123456,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "type": "private"
+    },
+    "date": 1584119424,
+    "text": "message"
+  }
+}
+

This will be needed for further use and We need to add it to the repo secrets which can be found in the repo settings. Be careful to add it as token and chat like as shown below +

+

Writing the Action and Building the Bot

+

Fire up the terminal/cmd and make a new folder. Install the dependencies. Run the following command

+
$ touch index.js action.yml
+

Open your favourite text editor within the folder or with the file. We’ll define the bot in index.js

+
require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+const {
+    INPUT_STATUS: ipstatus,
+    INPUT_TOKEN: tgtoken,//Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor,// Issue made by
+    INPUT_IU_BODY: ibody,// Issue Body
+    INPUT_PR_NUM: pnum,// PR Number
+    INPUT_PR_STATE: prstate,// PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle,// PR Title
+    INPUT_PR_BODY: pbody,// Body of the PR
+    GITHUB_EVENT_NAME: ghevent,// Name of the trigger event
+    GITHUB_REPOSITORY: repo,// Repository the trigger was made from
+    GITHUB_ACTOR: ghactor,// User who triggered the action
+    GITHUB_SHA: sha,// Commit ID
+    GITHUB_WORKFLOW: ghwrkflw// Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+

First, we’re defining the dotenv for config and initializing Telegram Bot. Here we’re defining the alias variables for the environment variables. You might notice an INPUT_ for almost every environment variable, this is because GitHub Actions pass the env variable with an INPUT prefix. Other env variables are action’s default environment variables. Then we initialized the bot with the API token.

+

GitHub actions could be triggered with Issues, Pull Request or Pushes. You can find the trigger events here. Here we’re gonna get a message from the bot when an Issue or Pull Request or a Push event has happened.

+
const evresp = (gevent) => {
+    switch (gevent) {
+
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+

In these lines of code, we’re just initializing a switch statement for the responses. We’re also declaring an anonymous function to use the switch responses via a function later. We’re using all the defined variables in the switch. You can check the trigger Events to get how the event is triggered and what keyword should be used.

+

Now for the last part of the Js file, we just take the response from the switch and assign it to a constant. Then we use the sendMessage function of the node-telegram-bot-api to send the message to the bot with the chatid and the output as the arguments.

+
const output = evresp(ghevent)
+

bot.sendMessage(chatid,output,{parse_mode : “Markdown”})

+

Compiling and Minifying the Js code

+

Since we have installed @zeit/ncc and this is used for the making the whole program with all the APIs to a single file and we need to use NCC for that. We just need to run

+
yarn run ncc build index.js -C -m -o dist
+

or you might wanna add the following to you package.json file, and run npm run test to compile and minify the code.

+
"scripts": {
+    "test": "ncc build index.js -C -m -o dist"
+  },
+

This will create a dist folder with and index.js file which contains the compiled code.

+

Making it a valid action

+

For making this Js file a valid action, we need to add an action.yml file. The action.yml for this action is like this

+
name: 'Action Name'
+description: 'Action Descreption'
+author: '<author name>'
+inputs: 
+  chat:
+    description: 'Chat to send: chat id or @channel_name'
+    required: true
+  token:
+    description: 'Telegram Bot token'
+    required: true
+  status:
+    description: 'Job status'
+    required: true
+  iu_title: 
+    description: 'Issue Title'
+    default: ${{ github.event.issue.title }}
+  iu_num:
+    description: 'Issue Number'
+    default: ${{ github.event.issue.number }}
+  iu_actor: 
+    description: 'Issue Triggerer'
+    default: ${{ github.event.issue.user.login }}
+  iu_com:
+    description: 'Issue Comment'
+    default: ${{github.event.comment.body}}
+  pr_state:
+    description: 'State of the PR'
+    default: ${{ github.event.action }}
+  pr_num:
+    description: 'PR Number'
+    default: ${{ github.event.number }}
+  pr_title:
+    description: 'Title of the PR'
+    default: ${{ github.event.pull_request.title }}
+  pr_body:
+    description: 'Body/Contents of the PR'
+    default: ${{ github.event.pull_request.body }}
+runs:
+  using: "node12"
+  main: "dist/index.js"
+branding:
+  icon: 'repeat'  
+  color: 'green'
+

Here we’re defining the Input variables to be loaded for the action in GitHub’s runtime environemt. All these default data are taken from the response of the webhooks which are send by GitHub when a trigger event is occured. You can find out more in the Action Documentation Here.

+
runs:
+  using: "node12"
+  main: "dist/index.js"
+

Here we are defining that this is a node action and should run in an environment with node, and the file which should be run, here the index.js file in the dist folder. That should do it. Create a new commit and push it to a repo. Create a new tag and this action will appear in the marketplace.

+

Defining a workflow to test your action

+

GitHub Action workflows are defined using the .yml syntax. Here is an example of a sample workflow for this action

+
name: <Workflow Name>
+
+on:
+  push:
+  pull_request:
+    types: [opened, closed]
+  issues:
+    types: [opened, closed, reopened]
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: <AnyName>
+        uses: <username>/<repo>@master
+        if: always()
+        with:
+          chat: ${{ secrets.chat }}
+          token: ${{ secrets.token }}
+          status: ${{ job.status }}
+

The Complete code for the bot is

+
//Initializing dotenv and the bot
+require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+// aliasing the environment variables 
+const {
+    INPUT_STATUS: ipstatus, 
+    INPUT_TOKEN: tgtoken, //Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor, // Issue made by
+    INPUT_IU_BODY: ibody, // Issue Body
+    INPUT_PR_NUM: pnum, // PR Number
+    INPUT_PR_STATE: prstate, // PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle, // PR Title
+    INPUT_PR_BODY: pbody, // Body of the PR
+    GITHUB_EVENT_NAME: ghevent, // Name of the trigger event
+    GITHUB_REPOSITORY: repo, // Repository the trigger was made from
+    GITHUB_ACTOR: ghactor, // User who triggered the action
+    GITHUB_SHA: sha, // Commit ID
+    GITHUB_WORKFLOW: ghwrkflw // Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+// Function to return the response for the specific trigger
+const evresp = (gevent) => {
+    switch (gevent) {
+//Switch statement for issues
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+// Switch statement for Pull Requests
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+// switch statement for Pushes
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+// assigning the output to a variable
+const output = evresp(ghevent)
+// sending the message
+bot.sendMessage(chatid,output,{parse_mode : "Markdown"})
+

+

You can try out many different items using actions and this is just a sample action to get you started. Maybe sending Cat GIFs if the build succeded on the pull request or sending a welcome message to a first time contributor. You imagination is the limit😄 and Never Stop being ⚡️

+ +
+ + +
+
+ +
+ + diff --git a/public/keywords/typography/index.html b/public/keywords/typography/index.html new file mode 100644 index 0000000..c2165cd --- /dev/null +++ b/public/keywords/typography/index.html @@ -0,0 +1,155 @@ + + + + Typography - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Typography

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 1

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 2

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 3

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 4

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 5
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 6
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Typography

+

Lid est laborum et dolorum fuga, This is an example inline link. Et harum quidem rerum facilis, This is bold and emphasis cumque nihilse impedit quo minus id quod amets untra dolor amet sad. While this is code block() and following is a pre tag

+
print 'this is pre tag'
+
+

Following is the syntax highlighted code block

+
func getCookie(name string, r interface{}) (*http.Cookie, error) {
+	rd := r.(*http.Request)
+	cookie, err := rd.Cookie(name)
+	if err != nil {
+		return nil, err
+	}
+	return cookie, nil
+}
+
+func setCookie(cookie *http.Cookie, w interface{}) error {
+	// Get write interface registered using `Acquire` method in handlers.
+	wr := w.(http.ResponseWriter)
+	http.SetCookie(wr, cookie)
+	return nil
+}
+

This is blockquote, Will make it better now

+
+

‘I want to do with you what spring does with the cherry trees.’ cited ~Pablo Neruda*

+
+
+

Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit

+
+

Unordered list

+
    +
  • Red
  • +
  • Green
  • +
  • Blue
  • +
+

Ordered list

+
    +
  1. Red
  2. +
  3. Green
  4. +
  5. Blue
  6. +
+ +
+ + +
+
+ +
+ + diff --git a/public/logo.jpg b/public/logo.jpg new file mode 100644 index 0000000..4c4dba5 Binary files /dev/null and b/public/logo.jpg differ diff --git a/public/new-post-on-archie/index.Rmarkdown b/public/new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..e9196ed --- /dev/null +++ b/public/new-post-on-archie/index.Rmarkdown @@ -0,0 +1,25 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? \ No newline at end of file diff --git a/public/new-post-on-archie/index.html b/public/new-post-on-archie/index.html new file mode 100644 index 0000000..630ab6b --- /dev/null +++ b/public/new-post-on-archie/index.html @@ -0,0 +1,126 @@ + + + + New Post on Archie - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

New Post on Archie

+
Posted on 2024-07-06
+
+ + +
+

Intro

+

This is my first post in the Archie template in hugo.

+

Here’s a random sample from the standard Normal distribution.

+
rnorm(5)
+
## [1] -0.3637057 -0.4214060  0.6501004 -0.8329920  1.3021409
+

Here’s an image of a duck.

+

+

Did I create a html from this?

+ +
+ + +
+
+ +
+ + diff --git a/public/page/1/index.html b/public/page/1/index.html new file mode 100644 index 0000000..9b9428b --- /dev/null +++ b/public/page/1/index.html @@ -0,0 +1,10 @@ + + + + //localhost:4321/ + + + + + + diff --git a/public/page/2/index.html b/public/page/2/index.html new file mode 100644 index 0000000..27bebdb --- /dev/null +++ b/public/page/2/index.html @@ -0,0 +1,150 @@ + + + + + The Median Duck | Home + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +

vires in notitia

+ + + +
+ + + +
+

Welcome!

+

+

Welcome to The Median Duck, a self initiated project that aims to +educate and entertain the general public on data analytic topics through +the hit UK TV show Taskmaster.

+

This project is in its early stages, but great things are planned; see +this vision document for the ambitious plans that I have in mind.

+
+

Your Time Starts Now!

+
+
+
+ +
+ + +

Latest Posts

+ +
+ + + + +
+ How I Learned to Stop Procrastinating, & Love Letting Go + +
+ +
+ Fearlessness: How to Stop Running from Space + +
+ + + + + + +
+ + +
+ + + diff --git a/public/post/2024-07-06-new-post-on-archie/index.Rmarkdown b/public/post/2024-07-06-new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..6c907ee --- /dev/null +++ b/public/post/2024-07-06-new-post-on-archie/index.Rmarkdown @@ -0,0 +1,21 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [] +tags: [] +draft: yes +--- + +# Intro +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +\[https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg] \ No newline at end of file diff --git a/public/post/2024-07-06-new-post-on-archie/index.html b/public/post/2024-07-06-new-post-on-archie/index.html new file mode 100644 index 0000000..fcf92d8 --- /dev/null +++ b/public/post/2024-07-06-new-post-on-archie/index.html @@ -0,0 +1,107 @@ + + + + New Post on Archie - Archie + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Archie +
+ +
+ +
+
+
+

New Post on Archie

+
Posted on Jul 6, 2024 DRAFT
+
+ + +
+

Intro

+

This is my first post in the Archie template in hugo.

+

Here’s a random sample from the standard Normal distribution.

+
rnorm(5)
+
## [1] -1.8403621  1.0484933  1.0183752  0.2850864 -0.4652938
+

Here’s an image of a duck.

+

[https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg]

+ +
+ + +
+
+ +
+ + diff --git a/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db b/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db differ diff --git a/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..fe84d35 --- /dev/null +++ b/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,170 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +slug: [] +categories: ["Getting Started", "Introduction", "Beginner", "Setup"] +tags: + - Introduction + - Setup + - Beginner + - Getting Started +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../") +``` + + +# Introduction and Objective +This article provides an overview of *Trabajo de las Mesas*, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. Really. + + +The article will also provide guidance on how to connect to the database from within . + +# Your Task +>Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now!l + +# *Trabajo de las Mesas* Database +*[Trabajo de las Mesas](https://tdlm.fly.dev/)* (TdlM^[Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +## Data Quality +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. . + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + + +## Why This Datasource? +As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + + +However, for the purposes of this project, being able to query from database has several advantages. This includes: +* Quality: Data being in a structured tabular format which often leads to better data quality +* Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc) +* Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + + +## Potential Areas to Explore in the Future +- Greater understanding of how the data is being collected. + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- Generate a data dictionary page + - What tables are available, samples of the data, what the table pertains to, and key columns. +- A dashboard on data quality. + - A highlevel overview of the quality and how recent the data is. + + +# Connecting to the Database from `R` + +## Downloading the `.db` file +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download} +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +repo_root_dir <- getwd() +db_file_name <- "taskmaster.db" +data_dir <- "Data" + +db_data_location <- file.path(repo_root_dir, data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(repo_root_dir, data_dir))){ + dir.create(file.path(repo_root_dir, data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` +## Connecting to the `.db` file +Now that the database file has been successfully downloaded, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + + +## Querying the Database +Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts +LEFT JOIN people tp +ON ts.id = tp.series +AND ts.champion = tp.id +" + +results <- dbGetQuery(tm_db, query) +results +``` + + +The results of this query already indicate interesting insights, namely that 204 days (approximately `r round(204/7)` weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag? + + +# Times Up! +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. \ No newline at end of file diff --git a/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.html b/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.html new file mode 100644 index 0000000..e1b29ee --- /dev/null +++ b/public/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.html @@ -0,0 +1,315 @@ + + + + Strength in Data: Connecting to the Taskmaster Database - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+

Strength in Data: Connecting to the Taskmaster Database

+
Posted on Jul 10, 2024 DRAFT
+
+ + +
+

Introduction and Objective

+

This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. Really.

+

The article will also provide guidance on how to connect to the database from within .

+

Your Task

+
+

Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now!l

+
+

Trabajo de las Mesas Database

+

Trabajo de las Mesas (TdlM^[Taskmaster fanatics will know that this is in reference to the hint in S2E5’s task Build a bridge for the potato., which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant.

+

The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project.

+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource. .

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+

Why This Datasource?

+

As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+

Potential Areas to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
    +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
    +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
    +
  • +
+

Connecting to the Database from R

+

Downloading the .db file

+

It is possible to view and query these the numerous tables in TdlM from the website itself. However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as R or python, naturally leads to repeatablility and reproduceability.

+

I opting choosing to choose R for this project due to my familarity with it, and the high level visualisations and modelling that can be employed.

+

The tables displayed on the website are powered from the following database file which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist.

+
# URL where Database file resides. We will download from here.
+db_url <- "https://tdlm.fly.dev/taskmaster.db"
+
+# Where the data will be stored locally
+repo_root_dir <- getwd()
+db_file_name <- "taskmaster.db"
+data_dir <- "Data"
+
+db_data_location <- file.path(repo_root_dir, data_dir, db_file_name)
+
+
+# Create Data Directory if does not exist
+if(!file.exists(file.path(repo_root_dir, data_dir))){
+    dir.create(file.path(repo_root_dir, data_dir))
+}
+
+# Download file specified by URL, save in the local destination.
+if(!file.exists(db_data_location)){
+    download.file(url = db_url, destfile = db_data_location, mode = "wb")
+}
+

Connecting to the .db file

+

Now that the database file has been successfully downloaded, we can start to connect to it from R directory. The DBI package will be employed to establish this connection.

+
package_name <- "RSQLite"
+
+if(!require(package_name, character.only = TRUE)){
+    install.packages(package_name, character.only = TRUE)
+} else{
+    library(package_name, character.only = TRUE)    
+}
+
## Loading required package: RSQLite
+
# Driver used to establish database connection
+sqlite_driver <- dbDriver("SQLite")
+
+# Making the connection 
+tm_db <- dbConnect(sqlite_driver, dbname = db_data_location)
+

If successful, we should be able to list all the tables included in the database.

+
# List all tables that are available in the database
+dbListTables(tm_db)
+
##  [1] "attempts"           "discrepancies"      "episode_scores"    
+##  [4] "episodes"           "intros"             "measurements"      
+##  [7] "normalized_scores"  "objectives"         "people"            
+## [10] "podcast"            "profanity"          "series"            
+## [13] "series_scores"      "special_locations"  "task_briefs"       
+## [16] "task_readers"       "task_winners"       "tasks"             
+## [19] "tasks_by_objective" "team_tasks"         "teams"             
+## [22] "title_coiners"      "title_stats"
+

Querying the Database

+

Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from R to access the data. For example:

+

A Basic SELECT query

+
# A Basic Select query  on the series table.
+query <- "SELECT * FROM series LIMIT 10"
+
+dbGetQuery(tm_db, query)
+
##    id     name episodes champion  air_start    air_end studio_start studio_end
+## 1  -7  CoC III        0       NA 2024-??-?? 2024-??-??   2023-11-28 2023-11-28
+## 2  -6 NYT 2024        0       NA 2024-01-01 2024-01-01   2023-11-27 2023-11-27
+## 3  -5 NYT 2023        1       96 2023-01-01 2023-01-01   2022-11-22 2022-11-22
+## 4  -4   CoC II        1       87 2022-06-23 2022-06-23   2021-09-15 2021-09-15
+## 5  -3 NYT 2022        1       73 2022-01-01 2022-01-01         <NA>       <NA>
+## 6  -2 NYT 2021        1       62 2021-01-01 2021-01-01         <NA>       <NA>
+## 7  -1      CoC        2       29 2017-12-13 2017-12-20   2017-11-20 2017-11-20
+## 8   1 Series 1        6        4 2015-07-28 2015-09-01   2015-03-23 2015-03-25
+## 9   2 Series 2        5       11 2016-06-21 2016-07-19         <NA>       <NA>
+## 10  3 Series 3        5       16 2016-10-04 2016-11-01         <NA>       <NA>
+##    points tasks special TMI
+## 1      NA    NA       1  88
+## 2      NA    NA       1  87
+## 3      76     5       1  66
+## 4      66     5       1  46
+## 5      68     5       1  47
+## 6      62     5       1  12
+## 7     164    10       1   6
+## 8     436    32       0   1
+## 9     417    28       0   2
+## 10    386    27       0   3
+

Advanced query

+

A more involved query involving JOIN and date manipulation

+
# A join, and data manipulation
+query <- "SELECT ts.name,
+ts.special as special_flag,
+tp.name as champion_name,
+tp.seat as chamption_seat,
+DATE(ts.studio_end) as studio_end, 
+DATE(ts.air_start) as air_start, 
+JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days
+FROM series ts
+LEFT JOIN people tp
+ON ts.id = tp.series
+AND ts.champion = tp.id
+"
+
+results <- dbGetQuery(tm_db, query)
+results
+
##         name special_flag    champion_name chamption_seat studio_end  air_start
+## 1    CoC III            1             <NA>             NA 2023-11-28       <NA>
+## 2   NYT 2024            1             <NA>             NA 2023-11-27 2024-01-01
+## 3   NYT 2023            1         Mo Farah              4 2022-11-22 2023-01-01
+## 4     CoC II            1  Richard Herring              5 2021-09-15 2022-06-23
+## 5   NYT 2022            1    Adrian Chiles              1       <NA> 2022-01-01
+## 6   NYT 2021            1   Shirley Ballas              5       <NA> 2021-01-01
+## 7        CoC            1  Josh Widdicombe              2 2017-11-20 2017-12-13
+## 8   Series 1            0  Josh Widdicombe              2 2015-03-25 2015-07-28
+## 9   Series 2            0   Katherine Ryan              4       <NA> 2016-06-21
+## 10  Series 3            0      Rob Beckett              4       <NA> 2016-10-04
+## 11  Series 4            0    Noel Fielding              5       <NA> 2017-04-25
+## 12  Series 5            0     Bob Mortimer              2 2017-07-06 2017-09-13
+## 13  Series 6            0     Liza Tarbuck              3 2018-03-28 2018-05-02
+## 14  Series 7            0   Kerry Godliman              3 2018-07-25 2018-09-05
+## 15  Series 8            0      Lou Sanders              3 2019-03-27 2019-05-08
+## 16  Series 9            0        Ed Gamble              2 2019-07-24 2019-09-04
+## 17 Series 10            0  Richard Herring              5 2020-07-29 2020-10-15
+## 18 Series 11            0    Sarah Kendall              5       <NA> 2021-03-18
+## 19 Series 12            0 Morgana Robinson              4       <NA> 2021-09-23
+## 20 Series 13            0     Sophie Duker              5 2021-09-22 2022-04-14
+## 21 Series 14            0    Dara Ó Briain              1 2022-05-05 2022-09-29
+## 22 Series 15            0       Mae Martin              5 2022-09-28 2023-03-30
+## 23 Series 16            0     Sam Campbell              3 2023-05-12 2023-09-21
+##    broadcast_lag_days
+## 1                  NA
+## 2                  35
+## 3                  40
+## 4                 281
+## 5                  NA
+## 6                  NA
+## 7                  23
+## 8                 125
+## 9                  NA
+## 10                 NA
+## 11                 NA
+## 12                 69
+## 13                 35
+## 14                 42
+## 15                 42
+## 16                 42
+## 17                 78
+## 18                 NA
+## 19                 NA
+## 20                204
+## 21                147
+## 22                183
+## 23                132
+

The results of this query already indicate interesting insights, namely that 204 days (approximately 29 weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag?

+

Times Up!

+

And that concludes this task! Hopefully you’ve been able to connect to the TdlM database directly through R and potentially inspired to start performing your own analysis.

+ +
+ + +
+
+ +
+ + diff --git a/public/post/index.html b/public/post/index.html new file mode 100644 index 0000000..0873b1d --- /dev/null +++ b/public/post/index.html @@ -0,0 +1,83 @@ + + + + Posts - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +

All articles

+ + + + +
+ + diff --git a/public/post/index.xml b/public/post/index.xml new file mode 100644 index 0000000..f9aed1a --- /dev/null +++ b/public/post/index.xml @@ -0,0 +1,20 @@ + + + + Posts on The Median Duck + http://localhost:4321/themedianduck/post/ + Recent content in Posts on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/ + + + + diff --git a/public/posts/2020-12-01-r-rmarkdown/index.Rmd b/public/posts/2020-12-01-r-rmarkdown/index.Rmd new file mode 100644 index 0000000..8768d78 --- /dev/null +++ b/public/posts/2020-12-01-r-rmarkdown/index.Rmd @@ -0,0 +1,38 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(collapse = TRUE) +``` + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + +```{r cars} +summary(cars) +fit <- lm(dist ~ speed, data = cars) +fit +``` + +# Including Plots + +You can also embed plots. See Figure \@ref(fig:pie) for example: + +```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE} +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` diff --git a/public/posts/2020-12-01-r-rmarkdown/index.html b/public/posts/2020-12-01-r-rmarkdown/index.html new file mode 100644 index 0000000..369e10d --- /dev/null +++ b/public/posts/2020-12-01-r-rmarkdown/index.html @@ -0,0 +1,174 @@ + + + + Hello R Markdown - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Hello R Markdown

+
Posted on Dec 1, 2020 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

R Markdown

+

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

+

You can embed an R code chunk like this:

+
summary(cars)
+##      speed           dist       
+##  Min.   : 4.0   Min.   :  2.00  
+##  1st Qu.:12.0   1st Qu.: 26.00  
+##  Median :15.0   Median : 36.00  
+##  Mean   :15.4   Mean   : 42.98  
+##  3rd Qu.:19.0   3rd Qu.: 56.00  
+##  Max.   :25.0   Max.   :120.00
+fit <- lm(dist ~ speed, data = cars)
+fit
+## 
+## Call:
+## lm(formula = dist ~ speed, data = cars)
+## 
+## Coefficients:
+## (Intercept)        speed  
+##     -17.579        3.932
+

Including Plots

+

You can also embed plots. See Figure 1 for example:

+
par(mar = c(0, 1, 0, 1))
+pie(
+  c(280, 60, 20),
+  c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
+  col = c('#0292D8', '#F7EA39', '#C4B632'),
+  init.angle = -50, border = NA
+)
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/2020-12-01-r-rmarkdown/index_files/figure-html/pie-1.png b/public/posts/2020-12-01-r-rmarkdown/index_files/figure-html/pie-1.png new file mode 100644 index 0000000..eef072f Binary files /dev/null and b/public/posts/2020-12-01-r-rmarkdown/index_files/figure-html/pie-1.png differ diff --git a/public/posts/2024-07-06-new-post-on-archie/index.Rmarkdown b/public/posts/2024-07-06-new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..e9196ed --- /dev/null +++ b/public/posts/2024-07-06-new-post-on-archie/index.Rmarkdown @@ -0,0 +1,25 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? \ No newline at end of file diff --git a/public/posts/2024-07-06-new-post-on-archie/index.html b/public/posts/2024-07-06-new-post-on-archie/index.html new file mode 100644 index 0000000..58c9f51 --- /dev/null +++ b/public/posts/2024-07-06-new-post-on-archie/index.html @@ -0,0 +1,148 @@ + + + + New Post on Archie - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

New Post on Archie

+
Posted on Jul 6, 2024
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

Intro

+

This is my first post in the Archie template in hugo.

+

Here’s a random sample from the standard Normal distribution.

+
rnorm(5)
+
## [1] -0.3637057 -0.4214060  0.6501004 -0.8329920  1.3021409
+

Here’s an image of a duck.

+

+

Did I create a html from this?

+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db b/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db differ diff --git a/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..3228ebe --- /dev/null +++ b/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,154 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +section: + - intro + - setup + - data +series: "Strength in Data" +tags: ["Strength in Data", "Beginner"] +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 2 + number_sections: true +--- + +```{r setup, include=FALSE, echo = FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../", + tidy = TRUE + ) +options(width = 1000) +``` + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +# Introduction and Objective + +This article provides an overview of *Trabajo de las Mesas*, a pivotal database that will be central to this project. + +The article will also provide guidance on how to connect to the database from within `R`. + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM [^1]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +[^1]: Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture. + + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +For some musings on TdlM, data quality and assumptions made, see this [post](/2024/07/data-quality-musings/). + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download, message = FALSE} +library(here) + +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +db_file_name <- "taskmaster.db" +data_dir <- here("static", "data") + +db_data_location <- file.path(data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(data_dir))){ + dir.create(file.path(data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` + +## Connecting to the `.db` file + +Now that the database file has been successfully downloaded, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + +## Querying the Database + +Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation + +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts +LEFT JOIN people tp +ON ts.id = tp.series +AND ts.champion = tp.id +WHERE ts.special <> 1 +" + +results <- dbGetQuery(tm_db, query) +results +``` + +The results of this query already indicate interesting insights, namely that 204 days (approximately `r round(204/7)` weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag? + +# Times Up! + +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.html b/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.html new file mode 100644 index 0000000..dd34300 --- /dev/null +++ b/public/posts/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/index.html @@ -0,0 +1,274 @@ + + + + Strength in Data: Connecting to the Taskmaster Database - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Strength in Data: Connecting to the Taskmaster Database

+
Posted on Jul 10, 2024
+
+ + + + +
+

Your Task

+
+

Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now!

+
+

Introduction and Objective

+

This article provides an overview of Trabajo de las Mesas, a pivotal database that will be central to this project.

+

The article will also provide guidance on how to connect to the database from within R.

+

Trabajo de las Mesas Database

+

Trabajo de las Mesas (TdlM 1) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant.

+

The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project.

+

For some musings on TdlM, data quality and assumptions made, see this post.

+

Connecting to the Database from R

+

Downloading the .db file

+

It is possible to view and query these the numerous tables in TdlM from the website itself. However, this does not lead intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as R or python, naturally leads to repeatablility and reproduceability.

+

I opting choosing to choose R for this project due to my familarity with it, and the high level visualisations and modelling that can be employed.

+

The tables displayed on the website are powered from the following database file which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist.

+
library(here)
+
+# URL where Database file resides. We will download from here.
+db_url <- "https://tdlm.fly.dev/taskmaster.db"
+
+# Where the data will be stored locally
+db_file_name <- "taskmaster.db"
+data_dir <- here("static", "data")
+
+db_data_location <- file.path(data_dir, db_file_name)
+
+
+# Create Data Directory if does not exist
+if (!file.exists(file.path(data_dir))) {
+    dir.create(file.path(data_dir))
+}
+
+# Download file specified by URL, save in the local destination.
+if (!file.exists(db_data_location)) {
+    download.file(url = db_url, destfile = db_data_location, mode = "wb")
+}
+

Connecting to the .db file

+

Now that the database file has been successfully downloaded, we can start to connect to it from R directory. The DBI package will be employed to establish this connection.

+
package_name <- "RSQLite"
+
+if (!require(package_name, character.only = TRUE)) {
+    install.packages(package_name, character.only = TRUE)
+} else {
+    library(package_name, character.only = TRUE)
+}
+
## Loading required package: RSQLite
+
# Driver used to establish database connection
+sqlite_driver <- dbDriver("SQLite")
+
+# Making the connection
+tm_db <- dbConnect(sqlite_driver, dbname = db_data_location)
+

If successful, we should be able to list all the tables included in the database.

+
# List all tables that are available in the database
+dbListTables(tm_db)
+
##  [1] "attempts"           "discrepancies"      "episode_scores"     "episodes"           "intros"             "measurements"       "normalized_scores"  "objectives"         "people"             "podcast"            "profanity"          "series"             "series_scores"      "special_locations"  "task_briefs"        "task_readers"       "task_winners"       "tasks"              "tasks_by_objective" "team_tasks"         "teams"              "title_coiners"      "title_stats"
+

Querying the Database

+

Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from R to access the data. For example:

+

A Basic SELECT query

+
# A Basic Select query on the series table.
+query <- "SELECT * FROM series LIMIT 10"
+
+dbGetQuery(tm_db, query)
+
##    id     name episodes champion  air_start    air_end studio_start studio_end points tasks special TMI
+## 1  -7  CoC III        0       NA 2024-??-?? 2024-??-??   2023-11-28 2023-11-28     NA    NA       1  88
+## 2  -6 NYT 2024        0       NA 2024-01-01 2024-01-01   2023-11-27 2023-11-27     NA    NA       1  87
+## 3  -5 NYT 2023        1       96 2023-01-01 2023-01-01   2022-11-22 2022-11-22     76     5       1  66
+## 4  -4   CoC II        1       87 2022-06-23 2022-06-23   2021-09-15 2021-09-15     66     5       1  46
+## 5  -3 NYT 2022        1       73 2022-01-01 2022-01-01         <NA>       <NA>     68     5       1  47
+## 6  -2 NYT 2021        1       62 2021-01-01 2021-01-01         <NA>       <NA>     62     5       1  12
+## 7  -1      CoC        2       29 2017-12-13 2017-12-20   2017-11-20 2017-11-20    164    10       1   6
+## 8   1 Series 1        6        4 2015-07-28 2015-09-01   2015-03-23 2015-03-25    436    32       0   1
+## 9   2 Series 2        5       11 2016-06-21 2016-07-19         <NA>       <NA>    417    28       0   2
+## 10  3 Series 3        5       16 2016-10-04 2016-11-01         <NA>       <NA>    386    27       0   3
+

Advanced query

+

A more involved query involving JOIN and date manipulation

+
# A join, and data manipulation
+query <- "SELECT ts.name,
+ts.special as special_flag,
+tp.name as champion_name,
+tp.seat as chamption_seat,
+DATE(ts.studio_end) as studio_end, 
+DATE(ts.air_start) as air_start, 
+JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days
+FROM series ts
+LEFT JOIN people tp
+ON ts.id = tp.series
+AND ts.champion = tp.id
+WHERE ts.special <> 1
+"
+
+results <- dbGetQuery(tm_db, query)
+results
+
##         name special_flag    champion_name chamption_seat studio_end  air_start broadcast_lag_days
+## 1   Series 1            0  Josh Widdicombe              2 2015-03-25 2015-07-28                125
+## 2   Series 2            0   Katherine Ryan              4       <NA> 2016-06-21                 NA
+## 3   Series 3            0      Rob Beckett              4       <NA> 2016-10-04                 NA
+## 4   Series 4            0    Noel Fielding              5       <NA> 2017-04-25                 NA
+## 5   Series 5            0     Bob Mortimer              2 2017-07-06 2017-09-13                 69
+## 6   Series 6            0     Liza Tarbuck              3 2018-03-28 2018-05-02                 35
+## 7   Series 7            0   Kerry Godliman              3 2018-07-25 2018-09-05                 42
+## 8   Series 8            0      Lou Sanders              3 2019-03-27 2019-05-08                 42
+## 9   Series 9            0        Ed Gamble              2 2019-07-24 2019-09-04                 42
+## 10 Series 10            0  Richard Herring              5 2020-07-29 2020-10-15                 78
+## 11 Series 11            0    Sarah Kendall              5       <NA> 2021-03-18                 NA
+## 12 Series 12            0 Morgana Robinson              4       <NA> 2021-09-23                 NA
+## 13 Series 13            0     Sophie Duker              5 2021-09-22 2022-04-14                204
+## 14 Series 14            0    Dara Ó Briain              1 2022-05-05 2022-09-29                147
+## 15 Series 15            0       Mae Martin              5 2022-09-28 2023-03-30                183
+## 16 Series 16            0     Sam Campbell              3 2023-05-12 2023-09-21                132
+

The results of this query already indicate interesting insights, namely that 204 days (approximately 29 weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag?

+

Times Up!

+

And that concludes this task! Hopefully you’ve been able to connect to the TdlM database directly through R and potentially inspired to start performing your own analysis.

+
+
+
    +
  1. +

    Taskmaster fanatics will know that this is in reference to the hint in S2E5’s task Build a bridge for the potato., which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture. ↩︎

    +
  2. +
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/2024-07-31-data-quality-musings/index.Rmd b/public/posts/2024-07-31-data-quality-musings/index.Rmd new file mode 100644 index 0000000..01f192e --- /dev/null +++ b/public/posts/2024-07-31-data-quality-musings/index.Rmd @@ -0,0 +1,9 @@ +--- +title: Data_Quality_Musings +author: Christopher Nam +date: '2024-07-31' +slug: data-quality-musings +categories: [] +tags: [] +draft: yes +--- diff --git a/public/posts/data-quality-musings/index.Rmd b/public/posts/data-quality-musings/index.Rmd new file mode 100644 index 0000000..bc496f5 --- /dev/null +++ b/public/posts/data-quality-musings/index.Rmd @@ -0,0 +1,49 @@ +--- +title: "Sidenote: Musings on TdlM" +author: Christopher Nam +date: '2024-07-17' +slug: data-quality-musings +categories: [] +tags: ["Musings", "TdlM"] +draft: no +--- + +# Sidenote Introduction +A few remarks and musings on the [Trabajo de las Mesas database (TdlM)](https://tdlm.fly.dev/). + +## Data Quality + +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occur and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + +## Why This Datasource? + +As Taskmaster is a global phenomena, there is no doubt other data sources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + +However, for the purposes of this project, being able to query from database has several advantages. This includes: + +- **Quality:** Data being in a structured tabular format which often leads to better data quality +- **Manipulations:** Greater manipulation and transformations could potentially be employed (joins, group bys etc) +- **Automation, Repeatability and Scalabilty:** if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis through a visual interface. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + +## Potential Articles to Explore in the Future + +- **Greater understanding of how the data is being collected.** + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- **Generate a data dictionary page** + - What tables are available, samples of the data, what the table pertains to, and key columns. +- **A dashboard on data quality.** + - A highlevel overview of the quality and how recent the data is. + - Can we be proactive in identifying data quality issues and resolve them before users of the data experience them. + diff --git a/public/posts/data-quality-musings/index.html b/public/posts/data-quality-musings/index.html new file mode 100644 index 0000000..78ccf53 --- /dev/null +++ b/public/posts/data-quality-musings/index.html @@ -0,0 +1,179 @@ + + + + Sidenote: Musings on TdlM - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Sidenote: Musings on TdlM

+
Posted on Jul 17, 2024
+
+ + +
+ +
+ +
+ + + +
+

Sidenote Introduction

+

A few remarks and musings on the Trabajo de las Mesas database (TdlM).

+
+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource.

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occur and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+
+
+

Why This Datasource?

+

As Taskmaster is a global phenomena, there is no doubt other data sources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis through a visual interface.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+
+
+

Potential Articles to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
    • Can we be proactive in identifying data quality issues and resolve them before users of the data experience them.
    • +
  • +
+
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/fearlessness-how-to-stop-running-from-space/index.html b/public/posts/fearlessness-how-to-stop-running-from-space/index.html new file mode 100644 index 0000000..29c5fb2 --- /dev/null +++ b/public/posts/fearlessness-how-to-stop-running-from-space/index.html @@ -0,0 +1,141 @@ + + + + Fearlessness: How to Stop Running from Space - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Fearlessness: How to Stop Running from Space

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos.

+

We are afraid of empty space in our lives.

+

The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives.

+

We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. We try to fill every second with activity, with something useful, as if silence and space are not valuable.

+

But what are we afraid of?

+

And who would we be if we didn’t have that fear?

+

We’re afraid of space and stillness and silence because it highlights the uncertainty, instability, groundlessness, insecurity, shakiness that lie underneath every second of our lives. We’re afraid of having to face this instability and uncertainty, of having to feel the fear of it.

+

Without the fear of all of the uncertainty that is highlighted by space … we become free.

+

I know in my life, when I allow myself to have stillness, silence, solitude, simplicity and space … it leaves room to face whatever is coming up for me. It gives me room to fully feel any feelings that I’ve been avoiding. It allows me to be more honest with myself, instead of using distractions and busyness to cover up what I don’t want to see.

+

And in the end, I develop trust that the space is not something to be feared, but rather something to be treasured. A gift, filled with learning and not knowing and shakiness and beauty.

+

You might try allowing more space to be in your day, without filling it:

+
    +
  • Take some time between tasks for stillness.
  • +
  • Sit out in nature, in silence, without technology.
  • +
  • When you notice yourself reaching for your phone, pause. See if you can just be still, just savor some space.
  • +
  • When you feel uncertainty or instability in your life (hint: it’s always there), let yourself feel it. Be present with it, without needing to run or avoid.
  • +
  • When you feel fear, be open-hearted with it and allow yourself fully feel it, being friendly with it. Your relationship with fear will change if you become friendly with it.
  • +
  • Do less, and trust that things won’t fall apart. Or if they do fall apart, you can be present with that instability.
  • +
  • When you’re in line, driving, eating, walking, exercising … see if you can do those things in silence, without technology, without needing to do something “useful.” Find the value in these spaces.
  • +
  • Notice who you are without the fear of space.
  • +
+

Savor these spaces, their deliciousness. Savor the groundlessness, as something filled with freedom if we learn not to fear it. Be present with the fear and uncertainty, as good friends not as enemies.

+

Let your heart be open raw tender and vulnerable, and your mind embracing the spaciousness of the vast blue sky of open awareness.

+ +
+ + +
+
+ +
+ + diff --git a/public/posts/getting-started-with-traveling-ultralight/index.html b/public/posts/getting-started-with-traveling-ultralight/index.html new file mode 100644 index 0000000..83c1ea7 --- /dev/null +++ b/public/posts/getting-started-with-traveling-ultralight/index.html @@ -0,0 +1,116 @@ + + + + Getting Started with Traveling Ultralight - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Getting Started with Traveling Ultralight

+
Posted on 2020-03-18 DRAFT
+
+ + +
+

I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said.

+

I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. But then I remembered that I’m far from normal in this way.

+

I gave him a tip for getting started, and I recommend it for all of you, who want to travel light — or ultralight, as I call it, because for many people traveling light is taking a carry-on roller luggage. For me, having those roller bags is lugging too much, because you can run up stairs with it with ease, or carry it all over a city without worrying about stowing away your luggage somewhere first. It’s so much easier to travel ultralight.

+

Here’s the tip I gave him to get started: start by getting a small backpack (less than 20 liters) and then just travel with what fits in that.

+

That’s how to start. But you’ll probably want some guidance on what to put into the bag, and how to travel with so little. Here’s some guidance to get started:

+
    +
  • I travel with a lightweight laptop (Macbook Air), a few clothes, my phone, earbuds and some charging cords, toiletries, and almost nothing else. A lightweight windbreaker for wind and light rain (Patagonia Houdini). An eye mask and ear plugs. A collapsible water bottle. My passport. That’s about it. No extra shoes. No books. No suit. No travel pillow. No extra camera other than my phone. I’m not sure what else everyone else brings, but none of that.
  • +
  • I bring clothes that I can wash in the sink or shower and that will dry overnight. Lightweight stuff that I can layer. Often they’re workout-style clothes or things from companies like Outlier or Patagonia that travel well. I don’t bring enough underwear or socks for every day of the trip, because I wash them every couple of days. I only bring one or two extra T-shirts, generally wearing the same two shirts the whole trip, even if it’s a month long. No one has ever once cared what I wear when I’m traveling.
  • +
  • I bring minimal toiletries: a small shaver for my head, razor, toothbrush, floss small tubes of toothpaste and shaving cream, deodorant, nail clippers, ibuprofen.
  • +
  • For cold places, I have thermal underwear and a couple long-sleeve layers (generally all Patagonia capilene stuff), and a beanie. I don’t usually go to places where it’s snowing (I don’t know why, maybe snow isn’t my thing), so I don’t have clothes to deal with that weather.
  • +
  • For warm places, I will bring flip flops and swim trunks, and leave most of the colder layers behind.
  • +
+

That’s enough for a monthlong trip, which I’ve done multiple times with this kind of setup. For a shorter trip of a few days, I might bring even less.

+

I really love traveling this way, and am more than willing to sacrifice bringing extra things for the luxury of traveling lightweight.

+

By the way, you don’t need much more than this kind of setup even in everyday life.

+

For more info on this, check out my Ultralight ebook, and my friend Tynan has a great book called Forever Nomad.

+ +
+ + +
+
+ +
+ + diff --git a/public/posts/hello-r-markdown/index.Rmd b/public/posts/hello-r-markdown/index.Rmd new file mode 100644 index 0000000..8768d78 --- /dev/null +++ b/public/posts/hello-r-markdown/index.Rmd @@ -0,0 +1,38 @@ +--- +title: "Hello R Markdown" +author: "Frida Gomam" +date: 2020-12-01T21:13:14-05:00 +categories: ["R"] +tags: ["R Markdown", "plot", "regression"] +draft: yes +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(collapse = TRUE) +``` + +# R Markdown + +This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see . + +You can embed an R code chunk like this: + +```{r cars} +summary(cars) +fit <- lm(dist ~ speed, data = cars) +fit +``` + +# Including Plots + +You can also embed plots. See Figure \@ref(fig:pie) for example: + +```{r pie, fig.cap='A fancy pie chart.', tidy=FALSE} +par(mar = c(0, 1, 0, 1)) +pie( + c(280, 60, 20), + c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'), + col = c('#0292D8', '#F7EA39', '#C4B632'), + init.angle = -50, border = NA +) +``` diff --git a/public/posts/hello-r-markdown/index.html b/public/posts/hello-r-markdown/index.html new file mode 100644 index 0000000..9b82f50 --- /dev/null +++ b/public/posts/hello-r-markdown/index.html @@ -0,0 +1,151 @@ + + + + Hello R Markdown - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Hello R Markdown

+
Posted on 2020-12-01 DRAFT
+
+ + +
+

R Markdown

+

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

+

You can embed an R code chunk like this:

+
summary(cars)
+##      speed           dist       
+##  Min.   : 4.0   Min.   :  2.00  
+##  1st Qu.:12.0   1st Qu.: 26.00  
+##  Median :15.0   Median : 36.00  
+##  Mean   :15.4   Mean   : 42.98  
+##  3rd Qu.:19.0   3rd Qu.: 56.00  
+##  Max.   :25.0   Max.   :120.00
+fit <- lm(dist ~ speed, data = cars)
+fit
+## 
+## Call:
+## lm(formula = dist ~ speed, data = cars)
+## 
+## Coefficients:
+## (Intercept)        speed  
+##     -17.579        3.932
+

Including Plots

+

You can also embed plots. See Figure 1 for example:

+
par(mar = c(0, 1, 0, 1))
+pie(
+  c(280, 60, 20),
+  c('Sky', 'Sunny side of pyramid', 'Shady side of pyramid'),
+  col = c('#0292D8', '#F7EA39', '#C4B632'),
+  init.angle = -50, border = NA
+)
+
+ +
+ + +
+
+ +
+ + diff --git a/public/posts/hello-r-markdown/index_files/figure-html/pie-1.png b/public/posts/hello-r-markdown/index_files/figure-html/pie-1.png new file mode 100644 index 0000000..eef072f Binary files /dev/null and b/public/posts/hello-r-markdown/index_files/figure-html/pie-1.png differ diff --git a/public/posts/how-i-learned-to-stop-procrastinating-love-letting-go/index.html b/public/posts/how-i-learned-to-stop-procrastinating-love-letting-go/index.html new file mode 100644 index 0000000..c3c7ad6 --- /dev/null +++ b/public/posts/how-i-learned-to-stop-procrastinating-love-letting-go/index.html @@ -0,0 +1,127 @@ + + + + How I Learned to Stop Procrastinating, & Love Letting Go - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

How I Learned to Stop Procrastinating, & Love Letting Go

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

The end of procrastination is the art of letting go.

+

I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done.

+

Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. It stressed me out. My work was less-than-desirable when I did it last minute. Slowly, I started to realize that procrastination wasn’t doing me any favors. In fact, it was causing me a lot of grief.

+

But I couldn’t quit. I tried a lot of things. I tried time boxing and goal setting and accountability and the Pomodoro Technique and Getting Things Done. All are great methods, but they only last so long. Nothing really worked over the long term.

+

That’s because I wasn’t getting to the root problem.

+

I hadn’t figured out the skill that would save me from the procrastination.

+

Until I learned about letting go.

+

Letting go first came to me when I was quitting smoking. I had to let go of the “need” to smoke, the use of my crutch of cigarettes to deal with stress and problems.

+

Then I learned I needed to let go of other false needs that were causing me problems: sugar, junk food, meat, shopping, beer, possessions. I’m not saying I can never do these things again once I let go of these needs, but I let go of the idea that they’re really necessary. I let go of an unhealthy attachment to them.

+

Then I learned that distractions and the false need to check my email and news and other things online … were causing me problems. They were causing my procrastination.

+

So I learned to let go of those too.

+

Here’s the process I used to let go of the distractions and false needs that cause procrastination:

+

I paid attention to the pain they cause me, later, instead of only the temporary comfort/pleasure they gave me right away. +I thought about the person I want to be, the life I want to live. I set my intentions to do the good work I think I should do. +I watched my urges to check things, to go to the comfort of distractions. I saw that I wanted to escape discomfort of something hard, and go to the comfort of something familiar and easy. +I realized I didn’t need that comfort. I could be in discomfort and nothing bad would happen. In fact, the best things happen when I’m in discomfort. +And then I smile, and breathe, and let go.

+

And one step at a time, become the person I want to be.

+ +
+ + +
+
+ +
+ + diff --git a/public/posts/how-to-test-dark-mode/index.html b/public/posts/how-to-test-dark-mode/index.html new file mode 100644 index 0000000..3f43d4e --- /dev/null +++ b/public/posts/how-to-test-dark-mode/index.html @@ -0,0 +1,112 @@ + + + + How to test dark mode? - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

How to test dark mode?

+
Posted on 2018-03-18 DRAFT
+
+ +
+ tl;dr: + Wubba lubba dub dub +
+ +
+

You can set dark mode as default by setting params.mode to dark in config.toml or set it to auto which will detect based on your OS and switch to dark mode. For more details refer documentation

+

Here is how you can switch based on your OS

+ + +
+ + +
+
+ +
+ + diff --git a/public/posts/hugo-shortcodes/index.html b/public/posts/hugo-shortcodes/index.html new file mode 100644 index 0000000..895c622 --- /dev/null +++ b/public/posts/hugo-shortcodes/index.html @@ -0,0 +1,355 @@ + + + + Hugo shortcodes - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+ +
+ +
+ + diff --git a/public/posts/index.html b/public/posts/index.html new file mode 100644 index 0000000..b36e132 --- /dev/null +++ b/public/posts/index.html @@ -0,0 +1,116 @@ + + + + Posts - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

All articles

+ + + + +
+ + diff --git a/public/posts/index.xml b/public/posts/index.xml new file mode 100644 index 0000000..842f401 --- /dev/null +++ b/public/posts/index.xml @@ -0,0 +1,97 @@ + + + + Posts on The Median Duck + //localhost:4321/posts/ + Recent content in Posts on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 17 Jul 2024 00:00:00 +0000 + + + Sidenote: Musings on TdlM + //localhost:4321/2024/07/data-quality-musings/ + Wed, 17 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/data-quality-musings/ + Sidenote Introduction Data Quality Why This Datasource? Potential Articles to Explore in the Future Sidenote Introduction A few remarks and musings on the Trabajo de las Mesas database (TdlM). Data Quality As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster. + + + Strength in Data: Connecting to the Taskmaster Database + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! This article provides an overview of Trabajo de las Mesas, a pivotal database that will be central to this project. The article will also provide guidance on how to connect to the database from within R. Trabajo de las Mesas Database Trabajo de las Mesas (TdlM 1) provides a plethora of data associated with Taskmaster in a database format. + + + New Post on Archie + //localhost:4321/2024/07/new-post-on-archie/ + Sat, 06 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/new-post-on-archie/ + Intro This is my first post in the Archie template in hugo. Here&rsquo;s a random sample from the standard Normal distribution. rnorm(5) ## [1] -0.3637057 -0.4214060 0.6501004 -0.8329920 1.3021409 Here&rsquo;s an image of a duck. Did I create a html from this? + + + Hello R Markdown + //localhost:4321/2020/12/hello-r-markdown/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/2020/12/hello-r-markdown/ + R Markdown This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com. You can embed an R code chunk like this: summary(cars) ## speed dist ## Min. : 4.0 Min. : 2.00 ## 1st Qu.:12.0 1st Qu.: 26.00 ## Median :15.0 Median : 36.00 ## Mean :15.4 Mean : 42.98 ## 3rd Qu. + + + Telegram Bot for GitHub Actions + //localhost:4321/2020/04/telegram-bot-for-github-actions/ + Wed, 01 Apr 2020 00:00:00 +0000 + //localhost:4321/2020/04/telegram-bot-for-github-actions/ + Telegram Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API. GitHub Actions GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. + + + Primer: When You Have Too Much to Do + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + Wed, 01 Apr 2020 02:01:58 +0530 + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more. It all keeps piling up, and it can feel overwhelming. How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate? + + + Getting Started with Traveling Ultralight + //localhost:4321/2020/03/getting-started-with-traveling-ultralight/ + Wed, 18 Mar 2020 12:13:35 +0530 + //localhost:4321/2020/03/getting-started-with-traveling-ultralight/ + I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said. I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. + + + How to test dark mode? + //localhost:4321/2018/03/how-to-test-dark-mode/ + Sun, 18 Mar 2018 12:13:38 +0530 + //localhost:4321/2018/03/how-to-test-dark-mode/ + Here is how you can setup dark mode for Ink and test on various OS like iOS, Android, macOS and Windows 10. + + + Typography + //localhost:4321/2018/03/typography/ + Sun, 18 Mar 2018 12:13:38 +0530 + //localhost:4321/2018/03/typography/ + Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. Heading 1 Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. + + + Hugo shortcodes + //localhost:4321/2018/03/hugo-shortcodes/ + Sun, 18 Mar 2018 12:13:36 +0530 + //localhost:4321/2018/03/hugo-shortcodes/ + Images Github Gist Youtube video Vimeo Instagram View this post on Instagram Callouts 💡 I guess this works + + + How I Learned to Stop Procrastinating, & Love Letting Go + //localhost:4321/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/ + Sun, 18 Mar 2018 12:13:32 +0530 + //localhost:4321/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/ + The end of procrastination is the art of letting go. I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done. Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. + + + Fearlessness: How to Stop Running from Space + //localhost:4321/2018/03/fearlessness-how-to-stop-running-from-space/ + Sun, 18 Mar 2018 12:13:30 +0530 + //localhost:4321/2018/03/fearlessness-how-to-stop-running-from-space/ + We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos. We are afraid of empty space in our lives. The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives. We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. + + + diff --git a/public/posts/new-post-on-archie/index.Rmarkdown b/public/posts/new-post-on-archie/index.Rmarkdown new file mode 100644 index 0000000..e9196ed --- /dev/null +++ b/public/posts/new-post-on-archie/index.Rmarkdown @@ -0,0 +1,25 @@ +--- +title: New Post on Archie +author: Christopher Nam +date: '2024-07-06' +slug: [] +categories: [trial, test] +tags: [hugo_test] +draft: no +--- + +# Intro + +This is my first post in the Archie template in hugo. + +Here's a random sample from the standard Normal distribution. + +```{r} +rnorm(5) +``` + +Here's an image of a duck. + +![](https://i.ebayimg.com/images/g/vToAAOSwr6hdW8L8/s-l1600.jpg) + +Did I create a html from this? \ No newline at end of file diff --git a/public/posts/new-post-on-archie/index.html b/public/posts/new-post-on-archie/index.html new file mode 100644 index 0000000..55e723e --- /dev/null +++ b/public/posts/new-post-on-archie/index.html @@ -0,0 +1,126 @@ + + + + New Post on Archie - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

New Post on Archie

+
Posted on 2024-07-06
+
+ + +
+

Intro

+

This is my first post in the Archie template in hugo.

+

Here’s a random sample from the standard Normal distribution.

+
rnorm(5)
+
## [1] -0.3637057 -0.4214060  0.6501004 -0.8329920  1.3021409
+

Here’s an image of a duck.

+

+

Did I create a html from this?

+ +
+ + +
+
+ +
+ + diff --git a/public/posts/post-1/index.html b/public/posts/post-1/index.html new file mode 100644 index 0000000..0bef5db --- /dev/null +++ b/public/posts/post-1/index.html @@ -0,0 +1,175 @@ + + + + Primer: When You Have Too Much to Do - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Primer: When You Have Too Much to Do

+
Posted on Apr 1, 2020 DRAFT
+
+ + + + +
+

You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more.

+

It all keeps piling up, and it can feel overwhelming.

+

How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate?

+

In this primer, I’ll look at some key strategies and tactics for taking on an overloaded life with an open heart, lots of energy, and a smile on your face.

+

The First Step: Triage

+

Whether you’re just starting your day, or you’re in the middle of the chaos and just need to find some sanity … the first step is to get into triage mode.

+

Triage, as you probably know, is sorting through the chaos to prioritize: what needs to be done now, what needs to be done today, what needs to be done this week, and what can wait? You’re looking at urgency, but also what’s meaningful and important.

+

Here’s what you might do:

+
    +
  • Pick out the things that need to be done today. Start a Short List for things you’re going to do today. That might be important tasks for big projects, urgent tasks that could result in damage if you don’t act, smaller admin tasks that you really should take care of today, and responding to important messages. I would recommend being ruthless and cutting out as much as you can, having just 5 things on your plate if that’s at all possible. Not everything needs to be done today, and not every email needs to be responded to.
  • +
  • Push some things to tomorrow and the rest of the week. If you have deadlines that can be pushed back (or renegotiated), do that. Spread the work out over the week, even into next week. What needs to be done tomorrow? What can wait a day or two longer?
  • +
  • Eliminate what you can. That might mean just not replying to some messages that aren’t that important and don’t really require a reply. It might mean telling some people that you can’t take on this project after all, or that you need to get out of the commitment that you said you’d do. Yes, this is uncomfortable. For now, just put them on a list called, “To Not Do,” and plan to figure out how to get out of them later.
  • +
+

OK, you have some breathing room and a manageable list now! Let’s shrink that down even further and just pick one thing.

+

Next: Focus on One Thing

+

With a lot on your plate, it’s hard to pick one thing to focus on. But that’s exactly what I’m going to ask you to do.

+

Pick one thing, and give it your focus. Yes, there are a lot of other things you can focus on. Yes, they’re stressing you out and making it hard to focus. But think about it this way: if you allow it all to be in your head all the time, that will always be your mode of being. You’ll always be thinking about everything, stressing out about it all, with a frazzled mind … unless you start shifting.

+

The shift:

+
    +
  • Pick something to focus on. Look at the triaged list from the first section … if you have 5-6 things on this Short List, you can assess whether there’s any super urgent, time-sensitive things you need to take care of. If there are, pick one of them. If not, pick the most important one — probably the one you have been putting off doing.
  • +
  • Clear everything else away. Just for a little bit. Close all browser tabs, turn off notifications, close open applications, put your phone away.
  • +
  • Put that one task before you, and allow yourself to be with it completely. Pour yourself into it. Think of it as a practice, of letting go (of everything else), of focus, of radical simplicity.
  • +
+

When you’re done (or after 15-20 minutes have gone by at least), you can switch to something else. But don’t allow yourself to switch until then.

+

By closing off all exits, by choosing one thing, by giving yourself completely to that thing … you’re now in a different mode that isn’t so stressful or spread thin. You’ve started a shift that will lead to focus and sanity.

+

Third: Schedule Time to Simplify

+

Remember the To Not Do list above? Schedule some time this week to start reducing your projects, saying no to people, getting out of commitments, crossing stuff off your task list … so that you can have some sanity back.

+

There are lots of little things that you’ve said “yes” to that you probably shouldn’t have. That’s why you’re overloaded. Protect your more important work, and your time off, and your peace of mind, by saying “no” to things that aren’t as important.

+

Schedule the time to simplify — you don’t have to do it today, but sometime soon — and you can then not have to worry about the things on your To Not Do list until then.

+

Fourth: Practice Mindful Focus

+

Go through the rest of the day with an attitude of “mindful focus.” That means that you are doing one thing at a time, being as present as you can, switching as little as you can.

+

Think of it as a settling of the mind. A new mode of being. A mindfulness practice (which means you won’t be perfect at it).

+

As you practice mindful focus, you’ll learn to practice doing things with an open heart, with curiosity and gratitude, and even joy. Try these one at a time as you get to do each task on your Short List.

+

You’ll find that you’re not so overloaded, but that each task is just perfect for that moment. And that’s a completely new relationship with the work that you do, and a new relationship with life.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/post-2/index.html b/public/posts/post-2/index.html new file mode 100644 index 0000000..2a711db --- /dev/null +++ b/public/posts/post-2/index.html @@ -0,0 +1,159 @@ + + + + Fearlessness: How to Stop Running from Space - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Fearlessness: How to Stop Running from Space

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos.

+

We are afraid of empty space in our lives.

+

The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives.

+

We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. We try to fill every second with activity, with something useful, as if silence and space are not valuable.

+

But what are we afraid of?

+

And who would we be if we didn’t have that fear?

+

We’re afraid of space and stillness and silence because it highlights the uncertainty, instability, groundlessness, insecurity, shakiness that lie underneath every second of our lives. We’re afraid of having to face this instability and uncertainty, of having to feel the fear of it.

+

Without the fear of all of the uncertainty that is highlighted by space … we become free.

+

I know in my life, when I allow myself to have stillness, silence, solitude, simplicity and space … it leaves room to face whatever is coming up for me. It gives me room to fully feel any feelings that I’ve been avoiding. It allows me to be more honest with myself, instead of using distractions and busyness to cover up what I don’t want to see.

+

And in the end, I develop trust that the space is not something to be feared, but rather something to be treasured. A gift, filled with learning and not knowing and shakiness and beauty.

+

You might try allowing more space to be in your day, without filling it:

+
    +
  • Take some time between tasks for stillness.
  • +
  • Sit out in nature, in silence, without technology.
  • +
  • When you notice yourself reaching for your phone, pause. See if you can just be still, just savor some space.
  • +
  • When you feel uncertainty or instability in your life (hint: it’s always there), let yourself feel it. Be present with it, without needing to run or avoid.
  • +
  • When you feel fear, be open-hearted with it and allow yourself fully feel it, being friendly with it. Your relationship with fear will change if you become friendly with it.
  • +
  • Do less, and trust that things won’t fall apart. Or if they do fall apart, you can be present with that instability.
  • +
  • When you’re in line, driving, eating, walking, exercising … see if you can do those things in silence, without technology, without needing to do something “useful.” Find the value in these spaces.
  • +
  • Notice who you are without the fear of space.
  • +
+

Savor these spaces, their deliciousness. Savor the groundlessness, as something filled with freedom if we learn not to fear it. Be present with the fear and uncertainty, as good friends not as enemies.

+

Let your heart be open raw tender and vulnerable, and your mind embracing the spaciousness of the vast blue sky of open awareness.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/post-3/index.html b/public/posts/post-3/index.html new file mode 100644 index 0000000..6284ae7 --- /dev/null +++ b/public/posts/post-3/index.html @@ -0,0 +1,145 @@ + + + + How I Learned to Stop Procrastinating, & Love Letting Go - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

How I Learned to Stop Procrastinating, & Love Letting Go

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

The end of procrastination is the art of letting go.

+

I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done.

+

Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. It stressed me out. My work was less-than-desirable when I did it last minute. Slowly, I started to realize that procrastination wasn’t doing me any favors. In fact, it was causing me a lot of grief.

+

But I couldn’t quit. I tried a lot of things. I tried time boxing and goal setting and accountability and the Pomodoro Technique and Getting Things Done. All are great methods, but they only last so long. Nothing really worked over the long term.

+

That’s because I wasn’t getting to the root problem.

+

I hadn’t figured out the skill that would save me from the procrastination.

+

Until I learned about letting go.

+

Letting go first came to me when I was quitting smoking. I had to let go of the “need” to smoke, the use of my crutch of cigarettes to deal with stress and problems.

+

Then I learned I needed to let go of other false needs that were causing me problems: sugar, junk food, meat, shopping, beer, possessions. I’m not saying I can never do these things again once I let go of these needs, but I let go of the idea that they’re really necessary. I let go of an unhealthy attachment to them.

+

Then I learned that distractions and the false need to check my email and news and other things online … were causing me problems. They were causing my procrastination.

+

So I learned to let go of those too.

+

Here’s the process I used to let go of the distractions and false needs that cause procrastination:

+

I paid attention to the pain they cause me, later, instead of only the temporary comfort/pleasure they gave me right away. +I thought about the person I want to be, the life I want to live. I set my intentions to do the good work I think I should do. +I watched my urges to check things, to go to the comfort of distractions. I saw that I wanted to escape discomfort of something hard, and go to the comfort of something familiar and easy. +I realized I didn’t need that comfort. I could be in discomfort and nothing bad would happen. In fact, the best things happen when I’m in discomfort. +And then I smile, and breathe, and let go.

+

And one step at a time, become the person I want to be.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/post-4/index.html b/public/posts/post-4/index.html new file mode 100644 index 0000000..090972b --- /dev/null +++ b/public/posts/post-4/index.html @@ -0,0 +1,133 @@ + + + + Getting Started with Traveling Ultralight - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Getting Started with Traveling Ultralight

+
Posted on Mar 18, 2020 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said.

+

I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. But then I remembered that I’m far from normal in this way.

+

I gave him a tip for getting started, and I recommend it for all of you, who want to travel light — or ultralight, as I call it, because for many people traveling light is taking a carry-on roller luggage. For me, having those roller bags is lugging too much, because you can run up stairs with it with ease, or carry it all over a city without worrying about stowing away your luggage somewhere first. It’s so much easier to travel ultralight.

+

Here’s the tip I gave him to get started: start by getting a small backpack (less than 20 liters) and then just travel with what fits in that.

+

That’s how to start. But you’ll probably want some guidance on what to put into the bag, and how to travel with so little. Here’s some guidance to get started:

+
    +
  • I travel with a lightweight laptop (Macbook Air), a few clothes, my phone, earbuds and some charging cords, toiletries, and almost nothing else. A lightweight windbreaker for wind and light rain (Patagonia Houdini). An eye mask and ear plugs. A collapsible water bottle. My passport. That’s about it. No extra shoes. No books. No suit. No travel pillow. No extra camera other than my phone. I’m not sure what else everyone else brings, but none of that.
  • +
  • I bring clothes that I can wash in the sink or shower and that will dry overnight. Lightweight stuff that I can layer. Often they’re workout-style clothes or things from companies like Outlier or Patagonia that travel well. I don’t bring enough underwear or socks for every day of the trip, because I wash them every couple of days. I only bring one or two extra T-shirts, generally wearing the same two shirts the whole trip, even if it’s a month long. No one has ever once cared what I wear when I’m traveling.
  • +
  • I bring minimal toiletries: a small shaver for my head, razor, toothbrush, floss small tubes of toothpaste and shaving cream, deodorant, nail clippers, ibuprofen.
  • +
  • For cold places, I have thermal underwear and a couple long-sleeve layers (generally all Patagonia capilene stuff), and a beanie. I don’t usually go to places where it’s snowing (I don’t know why, maybe snow isn’t my thing), so I don’t have clothes to deal with that weather.
  • +
  • For warm places, I will bring flip flops and swim trunks, and leave most of the colder layers behind.
  • +
+

That’s enough for a monthlong trip, which I’ve done multiple times with this kind of setup. For a shorter trip of a few days, I might bring even less.

+

I really love traveling this way, and am more than willing to sacrifice bringing extra things for the luxury of traveling lightweight.

+

By the way, you don’t need much more than this kind of setup even in everyday life.

+

For more info on this, check out my Ultralight ebook, and my friend Tynan has a great book called Forever Nomad.

+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/post-5/index.html b/public/posts/post-5/index.html new file mode 100644 index 0000000..05cd795 --- /dev/null +++ b/public/posts/post-5/index.html @@ -0,0 +1,181 @@ + + + + Typography - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Typography

+
Posted on Mar 18, 2018 DRAFT
+
+ + +
+ +

Table of Contents

+ + +
+ +
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 1

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 2

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 3

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 4

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 5
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 6
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Typography

+

Lid est laborum et dolorum fuga, This is an example inline link. Et harum quidem rerum facilis, This is bold and emphasis cumque nihilse impedit quo minus id quod amets untra dolor amet sad. While this is code block() and following is a pre tag

+
print 'this is pre tag'
+
+

Following is the syntax highlighted code block

+
func getCookie(name string, r interface{}) (*http.Cookie, error) {
+	rd := r.(*http.Request)
+	cookie, err := rd.Cookie(name)
+	if err != nil {
+		return nil, err
+	}
+	return cookie, nil
+}
+
+func setCookie(cookie *http.Cookie, w interface{}) error {
+	// Get write interface registered using `Acquire` method in handlers.
+	wr := w.(http.ResponseWriter)
+	http.SetCookie(wr, cookie)
+	return nil
+}
+

This is blockquote, Will make it better now

+
+

‘I want to do with you what spring does with the cherry trees.’ cited ~Pablo Neruda*

+
+
+

Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit

+
+

Unordered list

+
    +
  • Red
  • +
  • Green
  • +
  • Blue
  • +
+

Ordered list

+
    +
  1. Red
  2. +
  3. Green
  4. +
  5. Blue
  6. +
+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/post-6/index.html b/public/posts/post-6/index.html new file mode 100644 index 0000000..50d2984 --- /dev/null +++ b/public/posts/post-6/index.html @@ -0,0 +1,385 @@ + + + + Hugo shortcodes - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+ +
+ +
+ + diff --git a/public/posts/post-7/index.html b/public/posts/post-7/index.html new file mode 100644 index 0000000..e622f17 --- /dev/null +++ b/public/posts/post-7/index.html @@ -0,0 +1,129 @@ + + + + How to test dark mode? - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

How to test dark mode?

+
Posted on Mar 18, 2018 DRAFT
+
+ +
+ tl;dr: + Wubba lubba dub dub +
+ +
+ +

Table of Contents

+ + +
+ +
+

You can set dark mode as default by setting params.mode to dark in config.toml or set it to auto which will detect based on your OS and switch to dark mode. For more details refer documentation

+

Here is how you can switch based on your OS

+ + +
+ + + + +
+
+ +
+ + diff --git a/public/posts/primer-when-you-have-too-much-to-do/index.html b/public/posts/primer-when-you-have-too-much-to-do/index.html new file mode 100644 index 0000000..1ff11f9 --- /dev/null +++ b/public/posts/primer-when-you-have-too-much-to-do/index.html @@ -0,0 +1,146 @@ + + + + Primer: When You Have Too Much to Do - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Primer: When You Have Too Much to Do

+
Posted on 2020-04-01 DRAFT
+
+ + +
+

You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more.

+

It all keeps piling up, and it can feel overwhelming.

+

How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate?

+

In this primer, I’ll look at some key strategies and tactics for taking on an overloaded life with an open heart, lots of energy, and a smile on your face.

+

The First Step: Triage

+

Whether you’re just starting your day, or you’re in the middle of the chaos and just need to find some sanity … the first step is to get into triage mode.

+

Triage, as you probably know, is sorting through the chaos to prioritize: what needs to be done now, what needs to be done today, what needs to be done this week, and what can wait? You’re looking at urgency, but also what’s meaningful and important.

+

Here’s what you might do:

+
    +
  • Pick out the things that need to be done today. Start a Short List for things you’re going to do today. That might be important tasks for big projects, urgent tasks that could result in damage if you don’t act, smaller admin tasks that you really should take care of today, and responding to important messages. I would recommend being ruthless and cutting out as much as you can, having just 5 things on your plate if that’s at all possible. Not everything needs to be done today, and not every email needs to be responded to.
  • +
  • Push some things to tomorrow and the rest of the week. If you have deadlines that can be pushed back (or renegotiated), do that. Spread the work out over the week, even into next week. What needs to be done tomorrow? What can wait a day or two longer?
  • +
  • Eliminate what you can. That might mean just not replying to some messages that aren’t that important and don’t really require a reply. It might mean telling some people that you can’t take on this project after all, or that you need to get out of the commitment that you said you’d do. Yes, this is uncomfortable. For now, just put them on a list called, “To Not Do,” and plan to figure out how to get out of them later.
  • +
+

OK, you have some breathing room and a manageable list now! Let’s shrink that down even further and just pick one thing.

+

Next: Focus on One Thing

+

With a lot on your plate, it’s hard to pick one thing to focus on. But that’s exactly what I’m going to ask you to do.

+

Pick one thing, and give it your focus. Yes, there are a lot of other things you can focus on. Yes, they’re stressing you out and making it hard to focus. But think about it this way: if you allow it all to be in your head all the time, that will always be your mode of being. You’ll always be thinking about everything, stressing out about it all, with a frazzled mind … unless you start shifting.

+

The shift:

+
    +
  • Pick something to focus on. Look at the triaged list from the first section … if you have 5-6 things on this Short List, you can assess whether there’s any super urgent, time-sensitive things you need to take care of. If there are, pick one of them. If not, pick the most important one — probably the one you have been putting off doing.
  • +
  • Clear everything else away. Just for a little bit. Close all browser tabs, turn off notifications, close open applications, put your phone away.
  • +
  • Put that one task before you, and allow yourself to be with it completely. Pour yourself into it. Think of it as a practice, of letting go (of everything else), of focus, of radical simplicity.
  • +
+

When you’re done (or after 15-20 minutes have gone by at least), you can switch to something else. But don’t allow yourself to switch until then.

+

By closing off all exits, by choosing one thing, by giving yourself completely to that thing … you’re now in a different mode that isn’t so stressful or spread thin. You’ve started a shift that will lead to focus and sanity.

+

Third: Schedule Time to Simplify

+

Remember the To Not Do list above? Schedule some time this week to start reducing your projects, saying no to people, getting out of commitments, crossing stuff off your task list … so that you can have some sanity back.

+

There are lots of little things that you’ve said “yes” to that you probably shouldn’t have. That’s why you’re overloaded. Protect your more important work, and your time off, and your peace of mind, by saying “no” to things that aren’t as important.

+

Schedule the time to simplify — you don’t have to do it today, but sometime soon — and you can then not have to worry about the things on your To Not Do list until then.

+

Fourth: Practice Mindful Focus

+

Go through the rest of the day with an attitude of “mindful focus.” That means that you are doing one thing at a time, being as present as you can, switching as little as you can.

+

Think of it as a settling of the mind. A new mode of being. A mindfulness practice (which means you won’t be perfect at it).

+

As you practice mindful focus, you’ll learn to practice doing things with an open heart, with curiosity and gratitude, and even joy. Try these one at a time as you get to do each task on your Short List.

+

You’ll find that you’re not so overloaded, but that each task is just perfect for that moment. And that’s a completely new relationship with the work that you do, and a new relationship with life.

+ +
+ + +
+
+ +
+ + diff --git a/public/posts/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db b/public/posts/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/public/posts/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db differ diff --git a/public/posts/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/public/posts/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..3724020 --- /dev/null +++ b/public/posts/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,183 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +section: + - intro + - setup + - data +series: "Stength in Data" +tag: + - Introduction + - Setup + - Beginner + - Getting Started +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 1 +--- + +```{r setup, include=FALSE, echo = FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../") +``` + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +# Introduction and Objective + +This article provides an overview of *Trabajo de las Mesas*, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC + +The article will also provide guidance on how to connect to the database from within . + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM^\[Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.\]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +## Data Quality + +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. . + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + +## Why This Datasource? + +As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + +However, for the purposes of this project, being able to query from database has several advantages. This includes: + +- Quality: Data being in a structured tabular format which often leads to better data quality +- Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc) +- Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + +## Potential Areas to Explore in the Future + +- Greater understanding of how the data is being collected. + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- Generate a data dictionary page + - What tables are available, samples of the data, what the table pertains to, and key columns. +- A dashboard on data quality. + - A highlevel overview of the quality and how recent the data is. + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download} +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +repo_root_dir <- getwd() +db_file_name <- "taskmaster.db" +data_dir <- "Data" + +db_data_location <- file.path(repo_root_dir, data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(repo_root_dir, data_dir))){ + dir.create(file.path(repo_root_dir, data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` + +## Connecting to the `.db` file + +Now that the database file has been successfully downloaded, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + +## Querying the Database + +Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation + +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts +LEFT JOIN people tp +ON ts.id = tp.series +AND ts.champion = tp.id +WHERE ts.special <> 1 +" + +results <- dbGetQuery(tm_db, query) +results +``` + +The results of this query already indicate interesting insights, namely that 204 days (approximately `r round(204/7)` weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag? + +# Times Up! + +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/public/posts/strength-in-data-connecting-to-the-taskmaster-database/index.html b/public/posts/strength-in-data-connecting-to-the-taskmaster-database/index.html new file mode 100644 index 0000000..25e7fb6 --- /dev/null +++ b/public/posts/strength-in-data-connecting-to-the-taskmaster-database/index.html @@ -0,0 +1,287 @@ + + + + Strength in Data: Connecting to the Taskmaster Database - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Strength in Data: Connecting to the Taskmaster Database

+
Posted on 2024-07-10
+
+ + +
+

Your Task

+
+

Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now!

+
+

Introduction and Objective

+

This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC

+

The article will also provide guidance on how to connect to the database from within .

+

Trabajo de las Mesas Database

+

Trabajo de las Mesas (TdlM^[Taskmaster fanatics will know that this is in reference to the hint in S2E5’s task Build a bridge for the potato., which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant.

+

The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project.

+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource. .

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+

Why This Datasource?

+

As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+

Potential Areas to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
    +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
    +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
    +
  • +
+

Connecting to the Database from R

+

Downloading the .db file

+

It is possible to view and query these the numerous tables in TdlM from the website itself. However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as R or python, naturally leads to repeatablility and reproduceability.

+

I opting choosing to choose R for this project due to my familarity with it, and the high level visualisations and modelling that can be employed.

+

The tables displayed on the website are powered from the following database file which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist.

+
# URL where Database file resides. We will download from here.
+db_url <- "https://tdlm.fly.dev/taskmaster.db"
+
+# Where the data will be stored locally
+repo_root_dir <- getwd()
+db_file_name <- "taskmaster.db"
+data_dir <- "Data"
+
+db_data_location <- file.path(repo_root_dir, data_dir, db_file_name)
+
+
+# Create Data Directory if does not exist
+if(!file.exists(file.path(repo_root_dir, data_dir))){
+    dir.create(file.path(repo_root_dir, data_dir))
+}
+
+# Download file specified by URL, save in the local destination.
+if(!file.exists(db_data_location)){
+    download.file(url = db_url, destfile = db_data_location, mode = "wb")
+}
+

Connecting to the .db file

+

Now that the database file has been successfully downloaded, we can start to connect to it from R directory. The DBI package will be employed to establish this connection.

+
package_name <- "RSQLite"
+
+if(!require(package_name, character.only = TRUE)){
+    install.packages(package_name, character.only = TRUE)
+} else{
+    library(package_name, character.only = TRUE)    
+}
+
## Loading required package: RSQLite
+
# Driver used to establish database connection
+sqlite_driver <- dbDriver("SQLite")
+
+# Making the connection 
+tm_db <- dbConnect(sqlite_driver, dbname = db_data_location)
+

If successful, we should be able to list all the tables included in the database.

+
# List all tables that are available in the database
+dbListTables(tm_db)
+
##  [1] "attempts"           "discrepancies"      "episode_scores"    
+##  [4] "episodes"           "intros"             "measurements"      
+##  [7] "normalized_scores"  "objectives"         "people"            
+## [10] "podcast"            "profanity"          "series"            
+## [13] "series_scores"      "special_locations"  "task_briefs"       
+## [16] "task_readers"       "task_winners"       "tasks"             
+## [19] "tasks_by_objective" "team_tasks"         "teams"             
+## [22] "title_coiners"      "title_stats"
+

Querying the Database

+

Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from R to access the data. For example:

+

A Basic SELECT query

+
# A Basic Select query  on the series table.
+query <- "SELECT * FROM series LIMIT 10"
+
+dbGetQuery(tm_db, query)
+
##    id     name episodes champion  air_start    air_end studio_start studio_end
+## 1  -7  CoC III        0       NA 2024-??-?? 2024-??-??   2023-11-28 2023-11-28
+## 2  -6 NYT 2024        0       NA 2024-01-01 2024-01-01   2023-11-27 2023-11-27
+## 3  -5 NYT 2023        1       96 2023-01-01 2023-01-01   2022-11-22 2022-11-22
+## 4  -4   CoC II        1       87 2022-06-23 2022-06-23   2021-09-15 2021-09-15
+## 5  -3 NYT 2022        1       73 2022-01-01 2022-01-01         <NA>       <NA>
+## 6  -2 NYT 2021        1       62 2021-01-01 2021-01-01         <NA>       <NA>
+## 7  -1      CoC        2       29 2017-12-13 2017-12-20   2017-11-20 2017-11-20
+## 8   1 Series 1        6        4 2015-07-28 2015-09-01   2015-03-23 2015-03-25
+## 9   2 Series 2        5       11 2016-06-21 2016-07-19         <NA>       <NA>
+## 10  3 Series 3        5       16 2016-10-04 2016-11-01         <NA>       <NA>
+##    points tasks special TMI
+## 1      NA    NA       1  88
+## 2      NA    NA       1  87
+## 3      76     5       1  66
+## 4      66     5       1  46
+## 5      68     5       1  47
+## 6      62     5       1  12
+## 7     164    10       1   6
+## 8     436    32       0   1
+## 9     417    28       0   2
+## 10    386    27       0   3
+

Advanced query

+

A more involved query involving JOIN and date manipulation

+
# A join, and data manipulation
+query <- "SELECT ts.name,
+ts.special as special_flag,
+tp.name as champion_name,
+tp.seat as chamption_seat,
+DATE(ts.studio_end) as studio_end, 
+DATE(ts.air_start) as air_start, 
+JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days
+FROM series ts
+LEFT JOIN people tp
+ON ts.id = tp.series
+AND ts.champion = tp.id
+WHERE ts.special <> 1
+"
+
+results <- dbGetQuery(tm_db, query)
+results
+
##         name special_flag    champion_name chamption_seat studio_end  air_start
+## 1   Series 1            0  Josh Widdicombe              2 2015-03-25 2015-07-28
+## 2   Series 2            0   Katherine Ryan              4       <NA> 2016-06-21
+## 3   Series 3            0      Rob Beckett              4       <NA> 2016-10-04
+## 4   Series 4            0    Noel Fielding              5       <NA> 2017-04-25
+## 5   Series 5            0     Bob Mortimer              2 2017-07-06 2017-09-13
+## 6   Series 6            0     Liza Tarbuck              3 2018-03-28 2018-05-02
+## 7   Series 7            0   Kerry Godliman              3 2018-07-25 2018-09-05
+## 8   Series 8            0      Lou Sanders              3 2019-03-27 2019-05-08
+## 9   Series 9            0        Ed Gamble              2 2019-07-24 2019-09-04
+## 10 Series 10            0  Richard Herring              5 2020-07-29 2020-10-15
+## 11 Series 11            0    Sarah Kendall              5       <NA> 2021-03-18
+## 12 Series 12            0 Morgana Robinson              4       <NA> 2021-09-23
+## 13 Series 13            0     Sophie Duker              5 2021-09-22 2022-04-14
+## 14 Series 14            0    Dara Ó Briain              1 2022-05-05 2022-09-29
+## 15 Series 15            0       Mae Martin              5 2022-09-28 2023-03-30
+## 16 Series 16            0     Sam Campbell              3 2023-05-12 2023-09-21
+##    broadcast_lag_days
+## 1                 125
+## 2                  NA
+## 3                  NA
+## 4                  NA
+## 5                  69
+## 6                  35
+## 7                  42
+## 8                  42
+## 9                  42
+## 10                 78
+## 11                 NA
+## 12                 NA
+## 13                204
+## 14                147
+## 15                183
+## 16                132
+

The results of this query already indicate interesting insights, namely that 204 days (approximately 29 weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag?

+

Times Up!

+

And that concludes this task! Hopefully you’ve been able to connect to the TdlM database directly through R and potentially inspired to start performing your own analysis.

+ +
+ + +
+
+ +
+ + diff --git a/public/posts/telegram-bot-for-github-actions/index.html b/public/posts/telegram-bot-for-github-actions/index.html new file mode 100644 index 0000000..daad861 --- /dev/null +++ b/public/posts/telegram-bot-for-github-actions/index.html @@ -0,0 +1,439 @@ + + + + Telegram Bot for GitHub Actions - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Telegram Bot for GitHub Actions

+
Posted on 2020-04-01 DRAFT
+
+ +
+ tl;dr: + Making GitHub Actions with Js Code +
+ +
+

Telegram

+

Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API.

+

GitHub Actions

+

GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. You can build, test and deploy your code with GitHub Actions. All these actions are called workflows and workflows differ in the job they’re doing. These maybe test workflows, build ones or deployment ones. You can find all the actions on GitHub in the marketplace

+

Building the Bot

+

Prerequisites

+
    +
  • Basic JavaScript Knowledge
  • +
  • Basic GitHub Knowledge
  • +
  • Telegram Account
  • +
+
+

There are templates for building actions. Here we’re gonna start from scratch

+
+

Environment Setup

+
    +
  • Node, You can download node from their website
  • +
  • NPM comes with node, so you don’t have to worry about it.
  • +
  • Initialize the Project
  • +
+
$ git init ## initialize a new git repository for version management
+---
+$ npm init
+
    +
  • dotenv, Dotenv can be downloaded via
  • +
+
$ npm i dotenv
+---
+$ yarn add dotenv
+
    +
  • node-telegram-bot-api, node-telegram-bot-api is a simple wrapper for building telegram bots. You can download it via
  • +
+
$ npm i node-telegram-bot-api
+---
+$ yarn add node-telegram-bot-api
+
    +
  • @zeit/ncc, NCC is a Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, GCC-style. It’s a dev dependency and can be downloaded
  • +
+
yarn add --dev @zeit/ncc
+---
+npm i -D @zeit/ncc
+

Folder Structure

+

The dist folder will be automatically created. action.yml will be made

+
.
+├── dist
+│   └── index.js
+├── index.js
+├── action.yml
+├── README.md
+└── package.json
+
    +
  • index.js is the file we’re defining the bot
  • +
  • action.yml is the file we’ll define the action and it’s behaviours
  • +
+

Making the Bot

+

We need to get an API bot token from telegram. For that Go to Telegram and Search for Botfather. It’s a bot. + +Create a new bot with the /newbot command and get the API key. We’ll need that, also talk to jsondump bot and get your chat id. The output may be like this, so

+
{
+  "update_id": 143943779,
+  "message": {
+    "message_id": 181575,
+    "from": {
+      "id": 123456 // this is what we need
+      "is_bot": false,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "language_code": "en"
+    },
+    "chat": {
+      "id": 123456,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "type": "private"
+    },
+    "date": 1584119424,
+    "text": "message"
+  }
+}
+

This will be needed for further use and We need to add it to the repo secrets which can be found in the repo settings. Be careful to add it as token and chat like as shown below +

+

Writing the Action and Building the Bot

+

Fire up the terminal/cmd and make a new folder. Install the dependencies. Run the following command

+
$ touch index.js action.yml
+

Open your favourite text editor within the folder or with the file. We’ll define the bot in index.js

+
require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+const {
+    INPUT_STATUS: ipstatus,
+    INPUT_TOKEN: tgtoken,//Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor,// Issue made by
+    INPUT_IU_BODY: ibody,// Issue Body
+    INPUT_PR_NUM: pnum,// PR Number
+    INPUT_PR_STATE: prstate,// PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle,// PR Title
+    INPUT_PR_BODY: pbody,// Body of the PR
+    GITHUB_EVENT_NAME: ghevent,// Name of the trigger event
+    GITHUB_REPOSITORY: repo,// Repository the trigger was made from
+    GITHUB_ACTOR: ghactor,// User who triggered the action
+    GITHUB_SHA: sha,// Commit ID
+    GITHUB_WORKFLOW: ghwrkflw// Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+

First, we’re defining the dotenv for config and initializing Telegram Bot. Here we’re defining the alias variables for the environment variables. You might notice an INPUT_ for almost every environment variable, this is because GitHub Actions pass the env variable with an INPUT prefix. Other env variables are action’s default environment variables. Then we initialized the bot with the API token.

+

GitHub actions could be triggered with Issues, Pull Request or Pushes. You can find the trigger events here. Here we’re gonna get a message from the bot when an Issue or Pull Request or a Push event has happened.

+
const evresp = (gevent) => {
+    switch (gevent) {
+
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+

In these lines of code, we’re just initializing a switch statement for the responses. We’re also declaring an anonymous function to use the switch responses via a function later. We’re using all the defined variables in the switch. You can check the trigger Events to get how the event is triggered and what keyword should be used.

+

Now for the last part of the Js file, we just take the response from the switch and assign it to a constant. Then we use the sendMessage function of the node-telegram-bot-api to send the message to the bot with the chatid and the output as the arguments.

+
const output = evresp(ghevent)
+

bot.sendMessage(chatid,output,{parse_mode : “Markdown”})

+

Compiling and Minifying the Js code

+

Since we have installed @zeit/ncc and this is used for the making the whole program with all the APIs to a single file and we need to use NCC for that. We just need to run

+
yarn run ncc build index.js -C -m -o dist
+

or you might wanna add the following to you package.json file, and run npm run test to compile and minify the code.

+
"scripts": {
+    "test": "ncc build index.js -C -m -o dist"
+  },
+

This will create a dist folder with and index.js file which contains the compiled code.

+

Making it a valid action

+

For making this Js file a valid action, we need to add an action.yml file. The action.yml for this action is like this

+
name: 'Action Name'
+description: 'Action Descreption'
+author: '<author name>'
+inputs: 
+  chat:
+    description: 'Chat to send: chat id or @channel_name'
+    required: true
+  token:
+    description: 'Telegram Bot token'
+    required: true
+  status:
+    description: 'Job status'
+    required: true
+  iu_title: 
+    description: 'Issue Title'
+    default: ${{ github.event.issue.title }}
+  iu_num:
+    description: 'Issue Number'
+    default: ${{ github.event.issue.number }}
+  iu_actor: 
+    description: 'Issue Triggerer'
+    default: ${{ github.event.issue.user.login }}
+  iu_com:
+    description: 'Issue Comment'
+    default: ${{github.event.comment.body}}
+  pr_state:
+    description: 'State of the PR'
+    default: ${{ github.event.action }}
+  pr_num:
+    description: 'PR Number'
+    default: ${{ github.event.number }}
+  pr_title:
+    description: 'Title of the PR'
+    default: ${{ github.event.pull_request.title }}
+  pr_body:
+    description: 'Body/Contents of the PR'
+    default: ${{ github.event.pull_request.body }}
+runs:
+  using: "node12"
+  main: "dist/index.js"
+branding:
+  icon: 'repeat'  
+  color: 'green'
+

Here we’re defining the Input variables to be loaded for the action in GitHub’s runtime environemt. All these default data are taken from the response of the webhooks which are send by GitHub when a trigger event is occured. You can find out more in the Action Documentation Here.

+
runs:
+  using: "node12"
+  main: "dist/index.js"
+

Here we are defining that this is a node action and should run in an environment with node, and the file which should be run, here the index.js file in the dist folder. That should do it. Create a new commit and push it to a repo. Create a new tag and this action will appear in the marketplace.

+

Defining a workflow to test your action

+

GitHub Action workflows are defined using the .yml syntax. Here is an example of a sample workflow for this action

+
name: <Workflow Name>
+
+on:
+  push:
+  pull_request:
+    types: [opened, closed]
+  issues:
+    types: [opened, closed, reopened]
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: <AnyName>
+        uses: <username>/<repo>@master
+        if: always()
+        with:
+          chat: ${{ secrets.chat }}
+          token: ${{ secrets.token }}
+          status: ${{ job.status }}
+

The Complete code for the bot is

+
//Initializing dotenv and the bot
+require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+// aliasing the environment variables 
+const {
+    INPUT_STATUS: ipstatus, 
+    INPUT_TOKEN: tgtoken, //Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor, // Issue made by
+    INPUT_IU_BODY: ibody, // Issue Body
+    INPUT_PR_NUM: pnum, // PR Number
+    INPUT_PR_STATE: prstate, // PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle, // PR Title
+    INPUT_PR_BODY: pbody, // Body of the PR
+    GITHUB_EVENT_NAME: ghevent, // Name of the trigger event
+    GITHUB_REPOSITORY: repo, // Repository the trigger was made from
+    GITHUB_ACTOR: ghactor, // User who triggered the action
+    GITHUB_SHA: sha, // Commit ID
+    GITHUB_WORKFLOW: ghwrkflw // Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+// Function to return the response for the specific trigger
+const evresp = (gevent) => {
+    switch (gevent) {
+//Switch statement for issues
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+// Switch statement for Pull Requests
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+// switch statement for Pushes
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+// assigning the output to a variable
+const output = evresp(ghevent)
+// sending the message
+bot.sendMessage(chatid,output,{parse_mode : "Markdown"})
+

+

You can try out many different items using actions and this is just a sample action to get you started. Maybe sending Cat GIFs if the build succeded on the pull request or sending a welcome message to a first time contributor. You imagination is the limit😄 and Never Stop being ⚡️

+ +
+ + +
+
+ +
+ + diff --git a/public/posts/tg-gh/index.html b/public/posts/tg-gh/index.html new file mode 100644 index 0000000..6e350f2 --- /dev/null +++ b/public/posts/tg-gh/index.html @@ -0,0 +1,469 @@ + + + + Telegram Bot for GitHub Actions - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Telegram Bot for GitHub Actions

+
Posted on Apr 1, 2020 DRAFT
+
+ +
+ tl;dr: + Making GitHub Actions with Js Code +
+ + + +
+

Telegram

+

Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API.

+

GitHub Actions

+

GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. You can build, test and deploy your code with GitHub Actions. All these actions are called workflows and workflows differ in the job they’re doing. These maybe test workflows, build ones or deployment ones. You can find all the actions on GitHub in the marketplace

+

Building the Bot

+

Prerequisites

+
    +
  • Basic JavaScript Knowledge
  • +
  • Basic GitHub Knowledge
  • +
  • Telegram Account
  • +
+
+

There are templates for building actions. Here we’re gonna start from scratch

+
+

Environment Setup

+
    +
  • Node, You can download node from their website
  • +
  • NPM comes with node, so you don’t have to worry about it.
  • +
  • Initialize the Project
  • +
+
$ git init ## initialize a new git repository for version management
+---
+$ npm init
+
    +
  • dotenv, Dotenv can be downloaded via
  • +
+
$ npm i dotenv
+---
+$ yarn add dotenv
+
    +
  • node-telegram-bot-api, node-telegram-bot-api is a simple wrapper for building telegram bots. You can download it via
  • +
+
$ npm i node-telegram-bot-api
+---
+$ yarn add node-telegram-bot-api
+
    +
  • @zeit/ncc, NCC is a Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, GCC-style. It’s a dev dependency and can be downloaded
  • +
+
yarn add --dev @zeit/ncc
+---
+npm i -D @zeit/ncc
+

Folder Structure

+

The dist folder will be automatically created. action.yml will be made

+
.
+├── dist
+│   └── index.js
+├── index.js
+├── action.yml
+├── README.md
+└── package.json
+
    +
  • index.js is the file we’re defining the bot
  • +
  • action.yml is the file we’ll define the action and it’s behaviours
  • +
+

Making the Bot

+

We need to get an API bot token from telegram. For that Go to Telegram and Search for Botfather. It’s a bot. + +Create a new bot with the /newbot command and get the API key. We’ll need that, also talk to jsondump bot and get your chat id. The output may be like this, so

+
{
+  "update_id": 143943779,
+  "message": {
+    "message_id": 181575,
+    "from": {
+      "id": 123456 // this is what we need
+      "is_bot": false,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "language_code": "en"
+    },
+    "chat": {
+      "id": 123456,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "type": "private"
+    },
+    "date": 1584119424,
+    "text": "message"
+  }
+}
+

This will be needed for further use and We need to add it to the repo secrets which can be found in the repo settings. Be careful to add it as token and chat like as shown below +

+

Writing the Action and Building the Bot

+

Fire up the terminal/cmd and make a new folder. Install the dependencies. Run the following command

+
$ touch index.js action.yml
+

Open your favourite text editor within the folder or with the file. We’ll define the bot in index.js

+
require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+const {
+    INPUT_STATUS: ipstatus,
+    INPUT_TOKEN: tgtoken,//Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor,// Issue made by
+    INPUT_IU_BODY: ibody,// Issue Body
+    INPUT_PR_NUM: pnum,// PR Number
+    INPUT_PR_STATE: prstate,// PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle,// PR Title
+    INPUT_PR_BODY: pbody,// Body of the PR
+    GITHUB_EVENT_NAME: ghevent,// Name of the trigger event
+    GITHUB_REPOSITORY: repo,// Repository the trigger was made from
+    GITHUB_ACTOR: ghactor,// User who triggered the action
+    GITHUB_SHA: sha,// Commit ID
+    GITHUB_WORKFLOW: ghwrkflw// Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+

First, we’re defining the dotenv for config and initializing Telegram Bot. Here we’re defining the alias variables for the environment variables. You might notice an INPUT_ for almost every environment variable, this is because GitHub Actions pass the env variable with an INPUT prefix. Other env variables are action’s default environment variables. Then we initialized the bot with the API token.

+

GitHub actions could be triggered with Issues, Pull Request or Pushes. You can find the trigger events here. Here we’re gonna get a message from the bot when an Issue or Pull Request or a Push event has happened.

+
const evresp = (gevent) => {
+    switch (gevent) {
+
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+

In these lines of code, we’re just initializing a switch statement for the responses. We’re also declaring an anonymous function to use the switch responses via a function later. We’re using all the defined variables in the switch. You can check the trigger Events to get how the event is triggered and what keyword should be used.

+

Now for the last part of the Js file, we just take the response from the switch and assign it to a constant. Then we use the sendMessage function of the node-telegram-bot-api to send the message to the bot with the chatid and the output as the arguments.

+
const output = evresp(ghevent)
+

bot.sendMessage(chatid,output,{parse_mode : “Markdown”})

+

Compiling and Minifying the Js code

+

Since we have installed @zeit/ncc and this is used for the making the whole program with all the APIs to a single file and we need to use NCC for that. We just need to run

+
yarn run ncc build index.js -C -m -o dist
+

or you might wanna add the following to you package.json file, and run npm run test to compile and minify the code.

+
"scripts": {
+    "test": "ncc build index.js -C -m -o dist"
+  },
+

This will create a dist folder with and index.js file which contains the compiled code.

+

Making it a valid action

+

For making this Js file a valid action, we need to add an action.yml file. The action.yml for this action is like this

+
name: 'Action Name'
+description: 'Action Descreption'
+author: '<author name>'
+inputs: 
+  chat:
+    description: 'Chat to send: chat id or @channel_name'
+    required: true
+  token:
+    description: 'Telegram Bot token'
+    required: true
+  status:
+    description: 'Job status'
+    required: true
+  iu_title: 
+    description: 'Issue Title'
+    default: ${{ github.event.issue.title }}
+  iu_num:
+    description: 'Issue Number'
+    default: ${{ github.event.issue.number }}
+  iu_actor: 
+    description: 'Issue Triggerer'
+    default: ${{ github.event.issue.user.login }}
+  iu_com:
+    description: 'Issue Comment'
+    default: ${{github.event.comment.body}}
+  pr_state:
+    description: 'State of the PR'
+    default: ${{ github.event.action }}
+  pr_num:
+    description: 'PR Number'
+    default: ${{ github.event.number }}
+  pr_title:
+    description: 'Title of the PR'
+    default: ${{ github.event.pull_request.title }}
+  pr_body:
+    description: 'Body/Contents of the PR'
+    default: ${{ github.event.pull_request.body }}
+runs:
+  using: "node12"
+  main: "dist/index.js"
+branding:
+  icon: 'repeat'  
+  color: 'green'
+

Here we’re defining the Input variables to be loaded for the action in GitHub’s runtime environemt. All these default data are taken from the response of the webhooks which are send by GitHub when a trigger event is occured. You can find out more in the Action Documentation Here.

+
runs:
+  using: "node12"
+  main: "dist/index.js"
+

Here we are defining that this is a node action and should run in an environment with node, and the file which should be run, here the index.js file in the dist folder. That should do it. Create a new commit and push it to a repo. Create a new tag and this action will appear in the marketplace.

+

Defining a workflow to test your action

+

GitHub Action workflows are defined using the .yml syntax. Here is an example of a sample workflow for this action

+
name: <Workflow Name>
+
+on:
+  push:
+  pull_request:
+    types: [opened, closed]
+  issues:
+    types: [opened, closed, reopened]
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: <AnyName>
+        uses: <username>/<repo>@master
+        if: always()
+        with:
+          chat: ${{ secrets.chat }}
+          token: ${{ secrets.token }}
+          status: ${{ job.status }}
+

The Complete code for the bot is

+
//Initializing dotenv and the bot
+require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+// aliasing the environment variables 
+const {
+    INPUT_STATUS: ipstatus, 
+    INPUT_TOKEN: tgtoken, //Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor, // Issue made by
+    INPUT_IU_BODY: ibody, // Issue Body
+    INPUT_PR_NUM: pnum, // PR Number
+    INPUT_PR_STATE: prstate, // PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle, // PR Title
+    INPUT_PR_BODY: pbody, // Body of the PR
+    GITHUB_EVENT_NAME: ghevent, // Name of the trigger event
+    GITHUB_REPOSITORY: repo, // Repository the trigger was made from
+    GITHUB_ACTOR: ghactor, // User who triggered the action
+    GITHUB_SHA: sha, // Commit ID
+    GITHUB_WORKFLOW: ghwrkflw // Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+// Function to return the response for the specific trigger
+const evresp = (gevent) => {
+    switch (gevent) {
+//Switch statement for issues
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+// Switch statement for Pull Requests
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+// switch statement for Pushes
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+// assigning the output to a variable
+const output = evresp(ghevent)
+// sending the message
+bot.sendMessage(chatid,output,{parse_mode : "Markdown"})
+

+

You can try out many different items using actions and this is just a sample action to get you started. Maybe sending Cat GIFs if the build succeded on the pull request or sending a welcome message to a first time contributor. You imagination is the limit😄 and Never Stop being ⚡️

+ +
+ + + + +
+
+ +
+ + diff --git a/public/posts/typography/index.html b/public/posts/typography/index.html new file mode 100644 index 0000000..5dd2abd --- /dev/null +++ b/public/posts/typography/index.html @@ -0,0 +1,155 @@ + + + + Typography - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Typography

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 1

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 2

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 3

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 4

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 5
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 6
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Typography

+

Lid est laborum et dolorum fuga, This is an example inline link. Et harum quidem rerum facilis, This is bold and emphasis cumque nihilse impedit quo minus id quod amets untra dolor amet sad. While this is code block() and following is a pre tag

+
print 'this is pre tag'
+
+

Following is the syntax highlighted code block

+
func getCookie(name string, r interface{}) (*http.Cookie, error) {
+	rd := r.(*http.Request)
+	cookie, err := rd.Cookie(name)
+	if err != nil {
+		return nil, err
+	}
+	return cookie, nil
+}
+
+func setCookie(cookie *http.Cookie, w interface{}) error {
+	// Get write interface registered using `Acquire` method in handlers.
+	wr := w.(http.ResponseWriter)
+	http.SetCookie(wr, cookie)
+	return nil
+}
+

This is blockquote, Will make it better now

+
+

‘I want to do with you what spring does with the cherry trees.’ cited ~Pablo Neruda*

+
+
+

Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit

+
+

Unordered list

+
    +
  • Red
  • +
  • Green
  • +
  • Blue
  • +
+

Ordered list

+
    +
  1. Red
  2. +
  3. Green
  4. +
  5. Blue
  6. +
+ +
+ + +
+
+ +
+ + diff --git a/public/primer-when-you-have-too-much-to-do/index.html b/public/primer-when-you-have-too-much-to-do/index.html new file mode 100644 index 0000000..94321d0 --- /dev/null +++ b/public/primer-when-you-have-too-much-to-do/index.html @@ -0,0 +1,146 @@ + + + + Primer: When You Have Too Much to Do - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Primer: When You Have Too Much to Do

+
Posted on 2020-04-01 DRAFT
+
+ + +
+

You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more.

+

It all keeps piling up, and it can feel overwhelming.

+

How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate?

+

In this primer, I’ll look at some key strategies and tactics for taking on an overloaded life with an open heart, lots of energy, and a smile on your face.

+

The First Step: Triage

+

Whether you’re just starting your day, or you’re in the middle of the chaos and just need to find some sanity … the first step is to get into triage mode.

+

Triage, as you probably know, is sorting through the chaos to prioritize: what needs to be done now, what needs to be done today, what needs to be done this week, and what can wait? You’re looking at urgency, but also what’s meaningful and important.

+

Here’s what you might do:

+
    +
  • Pick out the things that need to be done today. Start a Short List for things you’re going to do today. That might be important tasks for big projects, urgent tasks that could result in damage if you don’t act, smaller admin tasks that you really should take care of today, and responding to important messages. I would recommend being ruthless and cutting out as much as you can, having just 5 things on your plate if that’s at all possible. Not everything needs to be done today, and not every email needs to be responded to.
  • +
  • Push some things to tomorrow and the rest of the week. If you have deadlines that can be pushed back (or renegotiated), do that. Spread the work out over the week, even into next week. What needs to be done tomorrow? What can wait a day or two longer?
  • +
  • Eliminate what you can. That might mean just not replying to some messages that aren’t that important and don’t really require a reply. It might mean telling some people that you can’t take on this project after all, or that you need to get out of the commitment that you said you’d do. Yes, this is uncomfortable. For now, just put them on a list called, “To Not Do,” and plan to figure out how to get out of them later.
  • +
+

OK, you have some breathing room and a manageable list now! Let’s shrink that down even further and just pick one thing.

+

Next: Focus on One Thing

+

With a lot on your plate, it’s hard to pick one thing to focus on. But that’s exactly what I’m going to ask you to do.

+

Pick one thing, and give it your focus. Yes, there are a lot of other things you can focus on. Yes, they’re stressing you out and making it hard to focus. But think about it this way: if you allow it all to be in your head all the time, that will always be your mode of being. You’ll always be thinking about everything, stressing out about it all, with a frazzled mind … unless you start shifting.

+

The shift:

+
    +
  • Pick something to focus on. Look at the triaged list from the first section … if you have 5-6 things on this Short List, you can assess whether there’s any super urgent, time-sensitive things you need to take care of. If there are, pick one of them. If not, pick the most important one — probably the one you have been putting off doing.
  • +
  • Clear everything else away. Just for a little bit. Close all browser tabs, turn off notifications, close open applications, put your phone away.
  • +
  • Put that one task before you, and allow yourself to be with it completely. Pour yourself into it. Think of it as a practice, of letting go (of everything else), of focus, of radical simplicity.
  • +
+

When you’re done (or after 15-20 minutes have gone by at least), you can switch to something else. But don’t allow yourself to switch until then.

+

By closing off all exits, by choosing one thing, by giving yourself completely to that thing … you’re now in a different mode that isn’t so stressful or spread thin. You’ve started a shift that will lead to focus and sanity.

+

Third: Schedule Time to Simplify

+

Remember the To Not Do list above? Schedule some time this week to start reducing your projects, saying no to people, getting out of commitments, crossing stuff off your task list … so that you can have some sanity back.

+

There are lots of little things that you’ve said “yes” to that you probably shouldn’t have. That’s why you’re overloaded. Protect your more important work, and your time off, and your peace of mind, by saying “no” to things that aren’t as important.

+

Schedule the time to simplify — you don’t have to do it today, but sometime soon — and you can then not have to worry about the things on your To Not Do list until then.

+

Fourth: Practice Mindful Focus

+

Go through the rest of the day with an attitude of “mindful focus.” That means that you are doing one thing at a time, being as present as you can, switching as little as you can.

+

Think of it as a settling of the mind. A new mode of being. A mindfulness practice (which means you won’t be perfect at it).

+

As you practice mindful focus, you’ll learn to practice doing things with an open heart, with curiosity and gratitude, and even joy. Try these one at a time as you get to do each task on your Short List.

+

You’ll find that you’re not so overloaded, but that each task is just perfect for that moment. And that’s a completely new relationship with the work that you do, and a new relationship with life.

+ +
+ + +
+
+ +
+ + diff --git a/public/resources/index.html b/public/resources/index.html new file mode 100644 index 0000000..b093b92 --- /dev/null +++ b/public/resources/index.html @@ -0,0 +1,134 @@ + + + + Resources - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+ +
+ +
+ + diff --git a/public/sections/data/index.html b/public/sections/data/index.html new file mode 100644 index 0000000..f2b5e32 --- /dev/null +++ b/public/sections/data/index.html @@ -0,0 +1,86 @@ + + + + Data - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "data"

+ + + + +
+ + diff --git a/public/sections/data/index.xml b/public/sections/data/index.xml new file mode 100644 index 0000000..021a59d --- /dev/null +++ b/public/sections/data/index.xml @@ -0,0 +1,20 @@ + + + + Data on The Median Duck + http://localhost:4321/themedianduck/sections/data/ + Recent content in Data on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/sections/index.html b/public/sections/index.html new file mode 100644 index 0000000..ba773ef --- /dev/null +++ b/public/sections/index.html @@ -0,0 +1,101 @@ + + + + Sections - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +

All tags

+ + + + + + + + +
+
    + +
+
+ +
+ + diff --git a/public/sections/index.xml b/public/sections/index.xml new file mode 100644 index 0000000..66d014b --- /dev/null +++ b/public/sections/index.xml @@ -0,0 +1,12 @@ + + + + Sections on The Median Duck + //localhost:4321/sections/ + Recent content in Sections on The Median Duck + Hugo + en-us + © Christopher Nam + + + diff --git a/public/sections/intro/index.html b/public/sections/intro/index.html new file mode 100644 index 0000000..6ddd60b --- /dev/null +++ b/public/sections/intro/index.html @@ -0,0 +1,86 @@ + + + + Intro - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "intro"

+ + + + +
+ + diff --git a/public/sections/intro/index.xml b/public/sections/intro/index.xml new file mode 100644 index 0000000..e2bd2f9 --- /dev/null +++ b/public/sections/intro/index.xml @@ -0,0 +1,20 @@ + + + + Intro on The Median Duck + http://localhost:4321/themedianduck/sections/intro/ + Recent content in Intro on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/sections/setup/index.html b/public/sections/setup/index.html new file mode 100644 index 0000000..39f6ebb --- /dev/null +++ b/public/sections/setup/index.html @@ -0,0 +1,86 @@ + + + + Setup - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "setup"

+ + + + +
+ + diff --git a/public/sections/setup/index.xml b/public/sections/setup/index.xml new file mode 100644 index 0000000..36ece28 --- /dev/null +++ b/public/sections/setup/index.xml @@ -0,0 +1,20 @@ + + + + Setup on The Median Duck + http://localhost:4321/themedianduck/sections/setup/ + Recent content in Setup on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/series/index.html b/public/series/index.html new file mode 100644 index 0000000..9834229 --- /dev/null +++ b/public/series/index.html @@ -0,0 +1,105 @@ + + + + Series - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +

All tags

+ + + + + + + + +
+ +
+ +
+ + diff --git a/public/series/index.xml b/public/series/index.xml new file mode 100644 index 0000000..e52306b --- /dev/null +++ b/public/series/index.xml @@ -0,0 +1,20 @@ + + + + Series on The Median Duck + //localhost:4321/series/ + Recent content in Series on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data + //localhost:4321/series/strength-in-data/ + Wed, 10 Jul 2024 00:00:00 +0000 + //localhost:4321/series/strength-in-data/ + + + + diff --git a/public/series/stength-in-data/index.html b/public/series/stength-in-data/index.html new file mode 100644 index 0000000..cdd9292 --- /dev/null +++ b/public/series/stength-in-data/index.html @@ -0,0 +1,94 @@ + + + + Stength in Data - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "Stength in Data"

+ + + + +
+ + diff --git a/public/series/stength-in-data/index.xml b/public/series/stength-in-data/index.xml new file mode 100644 index 0000000..f6ce789 --- /dev/null +++ b/public/series/stength-in-data/index.xml @@ -0,0 +1,20 @@ + + + + Stength in Data on The Median Duck + http://localhost:4321/themedianduck/series/stength-in-data/ + Recent content in Stength in Data on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/2024/07/10/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/series/strength-in-data/index.html b/public/series/strength-in-data/index.html new file mode 100644 index 0000000..12ad525 --- /dev/null +++ b/public/series/strength-in-data/index.html @@ -0,0 +1,94 @@ + + + + Strength in Data - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "Strength in Data"

+ + + + +
+ + diff --git a/public/series/strength-in-data/index.xml b/public/series/strength-in-data/index.xml new file mode 100644 index 0000000..7dbb4ee --- /dev/null +++ b/public/series/strength-in-data/index.xml @@ -0,0 +1,20 @@ + + + + Strength in Data on The Median Duck + //localhost:4321/series/strength-in-data/ + Recent content in Strength in Data on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! This article provides an overview of Trabajo de las Mesas, a pivotal database that will be central to this project. The article will also provide guidance on how to connect to the database from within R. Trabajo de las Mesas Database Trabajo de las Mesas (TdlM 1) provides a plethora of data associated with Taskmaster in a database format. + + + diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..39a8d7b --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,121 @@ + + + + //localhost:4321/tags/musings/ + 2024-07-17T00:00:00+00:00 + + //localhost:4321/posts/ + 2024-07-17T00:00:00+00:00 + + //localhost:4321/2024/07/data-quality-musings/ + 2024-07-17T00:00:00+00:00 + + //localhost:4321/tags/ + 2024-07-17T00:00:00+00:00 + + //localhost:4321/tags/tdlm/ + 2024-07-17T00:00:00+00:00 + + //localhost:4321/ + 2024-07-17T00:00:00+00:00 + + //localhost:4321/tasks/ + 2024-07-17T00:00:00+00:00 + + //localhost:4321/tags/beginner/ + 2024-07-10T00:00:00+00:00 + + //localhost:4321/series/ + 2024-07-10T00:00:00+00:00 + + //localhost:4321/tags/strength-in-data/ + 2024-07-10T00:00:00+00:00 + + //localhost:4321/series/strength-in-data/ + 2024-07-10T00:00:00+00:00 + + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + 2024-07-10T00:00:00+00:00 + + //localhost:4321/about/ + 2024-07-08T00:00:00+00:00 + + //localhost:4321/categories/ + 2024-07-06T00:00:00+00:00 + + //localhost:4321/tags/hugo_test/ + 2024-07-06T00:00:00+00:00 + + //localhost:4321/2024/07/new-post-on-archie/ + 2024-07-06T00:00:00+00:00 + + //localhost:4321/categories/test/ + 2024-07-06T00:00:00+00:00 + + //localhost:4321/categories/trial/ + 2024-07-06T00:00:00+00:00 + + //localhost:4321/resources/ + 2024-07-04T00:00:00+00:00 + + //localhost:4321/vision/ + 2024-07-04T00:00:00+00:00 + + //localhost:4321/2020/12/hello-r-markdown/ + 2020-12-01T21:13:14-05:00 + + //localhost:4321/tags/plot/ + 2020-12-01T21:13:14-05:00 + + //localhost:4321/categories/r/ + 2020-12-01T21:13:14-05:00 + + //localhost:4321/tags/r-markdown/ + 2020-12-01T21:13:14-05:00 + + //localhost:4321/tags/regression/ + 2020-12-01T21:13:14-05:00 + + //localhost:4321/2020/04/telegram-bot-for-github-actions/ + 2020-04-01T00:00:00+00:00 + + //localhost:4321/tags/primer/ + 2020-04-01T02:01:58+05:30 + + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + 2020-04-01T02:01:58+05:30 + + //localhost:4321/tags/todo/ + 2020-04-01T02:01:58+05:30 + + //localhost:4321/2020/03/getting-started-with-traveling-ultralight/ + 2020-03-18T12:13:35+05:30 + + //localhost:4321/archives/ + 2019-05-28T00:00:00+00:00 + + //localhost:4321/2018/03/how-to-test-dark-mode/ + 2018-03-18T12:13:38+05:30 + + //localhost:4321/2018/03/typography/ + 2018-03-18T12:13:38+05:30 + + //localhost:4321/2018/03/hugo-shortcodes/ + 2018-03-18T12:13:36+05:30 + + //localhost:4321/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/ + 2018-03-18T12:13:32+05:30 + + //localhost:4321/tags/procrastinating/ + 2018-03-18T12:13:32+05:30 + + //localhost:4321/2018/03/fearlessness-how-to-stop-running-from-space/ + 2018-03-18T12:13:30+05:30 + + //localhost:4321/tags/space/ + 2018-03-18T12:13:30+05:30 + + //localhost:4321/sections/ + + diff --git a/public/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db b/public/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/public/strength-in-data-connecting-to-the-taskmaster-database/Data/taskmaster.db differ diff --git a/public/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown b/public/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown new file mode 100644 index 0000000..c6e7b0d --- /dev/null +++ b/public/strength-in-data-connecting-to-the-taskmaster-database/index.Rmarkdown @@ -0,0 +1,180 @@ +--- +title: 'Strength in Data: Connecting to the Taskmaster Database' +author: Christopher Nam +date: '2024-07-10' +keywords: ["intro", "setup"] +sections: ["intro", "setup", "data"] +categories: ["Getting Started", "Introduction", "Beginner", "Setup"] +tags: + - Introduction + - Setup + - Beginner + - Getting Started +draft: no +output: + blogdown::html_page: + toc: true + toc_depth: 1 +--- + +```{r setup, include=FALSE, echo = FALSE} +knitr::opts_chunk$set(echo = TRUE, root.dir = "../") +``` + +# Your Task + +> Successfully connect to the Taskmaster database from within `R`. Fastest wins; your time starts now! + +# Introduction and Objective + +This article provides an overview of *Trabajo de las Mesas*, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC + +The article will also provide guidance on how to connect to the database from within . + +# *Trabajo de las Mesas* Database + +[*Trabajo de las Mesas*](https://tdlm.fly.dev/) (TdlM^\[Taskmaster fanatics will know that this is in reference to the hint in S2E5's task *Build a bridge for the potato.*, which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.\]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant. + +The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project. + +## Data Quality + +As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. + +I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from [taskmaster.info](https://taskmaster.info/), an equally exhaustive Taskmaster resource. . + +For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.). + +If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more. + +## Why This Datasource? + +As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive [Google sheet document](https://docs.google.com/spreadsheets/d/1Us84BGInJw8Ef32xCVSVNo1W5mjri9CpUffYfLnq5xA/edit?usp=sharing) in which similar analysis and modelling could be performed. + +However, for the purposes of this project, being able to query from database has several advantages. This includes: + +- Quality: Data being in a structured tabular format which often leads to better data quality +- Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc) +- Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database. + +However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis. + +Considering overall vision of The Median Duck, I believe that a database approach is ideal. + +## Potential Areas to Explore in the Future + +- Greater understanding of how the data is being collected. + - Is it manual, and are their quality checks in place? Is there any opportunity to automate? + - Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don't appear to be present, despite being broadcasted already. + - Introduction of an ETL timestamp. +- Generate a data dictionary page + - What tables are available, samples of the data, what the table pertains to, and key columns. +- A dashboard on data quality. + - A highlevel overview of the quality and how recent the data is. + +# Connecting to the Database from `R` + +## Downloading the `.db` file + +It is possible to view and query these the numerous tables in TdlM from the [website itself](https://tdlm.fly.dev/). However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as `R` or `python`, naturally leads to repeatablility and reproduceability. + +I opting choosing to choose `R` for this project due to my familarity with it, and the high level visualisations and modelling that can be employed. + +The tables displayed on the website are powered from the following [database file](https://tdlm.fly.dev/taskmaster.db) which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist. + +```{r download} +# URL where Database file resides. We will download from here. +db_url <- "https://tdlm.fly.dev/taskmaster.db" + +# Where the data will be stored locally +repo_root_dir <- getwd() +db_file_name <- "taskmaster.db" +data_dir <- "Data" + +db_data_location <- file.path(repo_root_dir, data_dir, db_file_name) + + +# Create Data Directory if does not exist +if(!file.exists(file.path(repo_root_dir, data_dir))){ + dir.create(file.path(repo_root_dir, data_dir)) +} + +# Download file specified by URL, save in the local destination. +if(!file.exists(db_data_location)){ + download.file(url = db_url, destfile = db_data_location, mode = "wb") +} + +``` + +## Connecting to the `.db` file + +Now that the database file has been successfully downloaded, we can start to connect to it from `R` directory. The `DBI` package will be employed to establish this connection. + +```{r db_connect} +package_name <- "RSQLite" + +if(!require(package_name, character.only = TRUE)){ + install.packages(package_name, character.only = TRUE) +} else{ + library(package_name, character.only = TRUE) +} + + +# Driver used to establish database connection +sqlite_driver <- dbDriver("SQLite") + +# Making the connection +tm_db <- dbConnect(sqlite_driver, dbname = db_data_location) + +``` + +If successful, we should be able to list all the tables included in the database. + +```{r list_tables} +# List all tables that are available in the database +dbListTables(tm_db) +``` + +## Querying the Database + +Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from `R` to access the data. For example: + +### A Basic `SELECT` query + +```{r cols.print=25, series_output} + +# A Basic Select query on the series table. +query <- "SELECT * FROM series LIMIT 10" + +dbGetQuery(tm_db, query) +``` + +### Advanced query + +A more involved query involving `JOIN` and date manipulation + +```{r max.print=25, advanced_query} +# A join, and data manipulation +query <- "SELECT ts.name, +ts.special as special_flag, +tp.name as champion_name, +tp.seat as chamption_seat, +DATE(ts.studio_end) as studio_end, +DATE(ts.air_start) as air_start, +JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days +FROM series ts +LEFT JOIN people tp +ON ts.id = tp.series +AND ts.champion = tp.id +WHERE ts.special <> 1 +" + +results <- dbGetQuery(tm_db, query) +results +``` + +The results of this query already indicate interesting insights, namely that 204 days (approximately `r round(204/7)` weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag? + +# Times Up! + +And that concludes this task! Hopefully you've been able to connect to the TdlM database directly through `R` and potentially inspired to start performing your own analysis. diff --git a/public/strength-in-data-connecting-to-the-taskmaster-database/index.html b/public/strength-in-data-connecting-to-the-taskmaster-database/index.html new file mode 100644 index 0000000..8899630 --- /dev/null +++ b/public/strength-in-data-connecting-to-the-taskmaster-database/index.html @@ -0,0 +1,305 @@ + + + + Strength in Data: Connecting to the Taskmaster Database - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Strength in Data: Connecting to the Taskmaster Database

+
Posted on 2024-07-10
+
+ + +
+

Your Task

+
+

Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now!

+
+

Introduction and Objective

+

This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC

+

The article will also provide guidance on how to connect to the database from within .

+

Trabajo de las Mesas Database

+

Trabajo de las Mesas (TdlM^[Taskmaster fanatics will know that this is in reference to the hint in S2E5’s task Build a bridge for the potato., which has since become one of key pieces of advice for all Taskmaster contestants. It has been suitably adapted for working on data tables in a database, rather than a piece of furniture.]) provides a plethora of data associated with Taskmaster in a database format. Data included in the database includes information pertaining to a series, episode, conntestant, task attempts, and even profanity uttered by a contestant.

+

The exhaustive nature of the data truly opens the door to potential questions we may want to answer in the Taskmaster universe. For this reasons, I am immensely grateful to the contributors of this project.

+

Data Quality

+

As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it.

+

I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster.info, an equally exhaustive Taskmaster resource. .

+

For now, and to not derail me from my initial interest and excitement on The Median Duck project, I will assume that the data is of high quality (accurate, consistent etc.).

+

If there are any instances where the data quality is suspect, and/or a contradictory insight or conclusion is identified, a deep dive will likely occurr and the deep dive process will like provide useful insight for any inspiring individuals hoping to get into data analytics more.

+

Why This Datasource?

+

As the Taskmaster is a global phenomena, there is no doubt other datasources that could be used for this project. Most noticeably, Jack Bernhadt has an exhaustive Google sheet document in which similar analysis and modelling could be performed.

+

However, for the purposes of this project, being able to query from database has several advantages. This includes:

+
    +
  • Quality: Data being in a structured tabular format which often leads to better data quality
  • +
  • Manipulations: Greater manipulation and transformations could potentially be employed (joins, group bys etc)
  • +
  • Automation, Repeatability and Scalabilty: if we wanted to repeat the same or similar analysis but on a new subset of data (for example updated data due to a new series being broadcast, or new parameters being employed), it is more convenient to do this in a structured data source such as a database.
  • +
+

However, a database approach is by no means perfect either. The barrier to entry is considerably higher than data stored in a spreadsheet (both adding, manipulating and analysing data), and spreadsheets are good for ad-hoc, interactive analysis.

+

Considering overall vision of The Median Duck, I believe that a database approach is ideal.

+

Potential Areas to Explore in the Future

+
    +
  • Greater understanding of how the data is being collected. +
      +
    • Is it manual, and are their quality checks in place? Is there any opportunity to automate?
    • +
    • Can we introduce a SLA (service level agreement) of when the data can be expected to be populated. Data associated with more recent seasons don’t appear to be present, despite being broadcasted already.
    • +
    • Introduction of an ETL timestamp.
    • +
    +
  • +
  • Generate a data dictionary page +
      +
    • What tables are available, samples of the data, what the table pertains to, and key columns.
    • +
    +
  • +
  • A dashboard on data quality. +
      +
    • A highlevel overview of the quality and how recent the data is.
    • +
    +
  • +
+

Connecting to the Database from R

+

Downloading the .db file

+

It is possible to view and query these the numerous tables in TdlM from the website itself. However, this does not lead to intuitively to repeatable and reproduceable analysis. Connecting to the database from a statistical programming language such as R or python, naturally leads to repeatablility and reproduceability.

+

I opting choosing to choose R for this project due to my familarity with it, and the high level visualisations and modelling that can be employed.

+

The tables displayed on the website are powered from the following database file which can downloaded and stored locally. The following code chunk downloads the database file locally (based on the repo directory); a corresponding folder location will be created if it does not already exist.

+
# URL where Database file resides. We will download from here.
+db_url <- "https://tdlm.fly.dev/taskmaster.db"
+
+# Where the data will be stored locally
+repo_root_dir <- getwd()
+db_file_name <- "taskmaster.db"
+data_dir <- "Data"
+
+db_data_location <- file.path(repo_root_dir, data_dir, db_file_name)
+
+
+# Create Data Directory if does not exist
+if(!file.exists(file.path(repo_root_dir, data_dir))){
+    dir.create(file.path(repo_root_dir, data_dir))
+}
+
+# Download file specified by URL, save in the local destination.
+if(!file.exists(db_data_location)){
+    download.file(url = db_url, destfile = db_data_location, mode = "wb")
+}
+

Connecting to the .db file

+

Now that the database file has been successfully downloaded, we can start to connect to it from R directory. The DBI package will be employed to establish this connection.

+
package_name <- "RSQLite"
+
+if(!require(package_name, character.only = TRUE)){
+    install.packages(package_name, character.only = TRUE)
+} else{
+    library(package_name, character.only = TRUE)    
+}
+
## Loading required package: RSQLite
+
# Driver used to establish database connection
+sqlite_driver <- dbDriver("SQLite")
+
+# Making the connection 
+tm_db <- dbConnect(sqlite_driver, dbname = db_data_location)
+

If successful, we should be able to list all the tables included in the database.

+
# List all tables that are available in the database
+dbListTables(tm_db)
+
##  [1] "attempts"           "discrepancies"      "episode_scores"    
+##  [4] "episodes"           "intros"             "measurements"      
+##  [7] "normalized_scores"  "objectives"         "people"            
+## [10] "podcast"            "profanity"          "series"            
+## [13] "series_scores"      "special_locations"  "task_briefs"       
+## [16] "task_readers"       "task_winners"       "tasks"             
+## [19] "tasks_by_objective" "team_tasks"         "teams"             
+## [22] "title_coiners"      "title_stats"
+

Querying the Database

+

Now that we are successfully able to connect to the database, we are able to write queries and execute them directly from R to access the data. For example:

+

A Basic SELECT query

+
# A Basic Select query  on the series table.
+query <- "SELECT * FROM series LIMIT 10"
+
+dbGetQuery(tm_db, query)
+
##    id     name episodes champion  air_start    air_end studio_start studio_end
+## 1  -7  CoC III        0       NA 2024-??-?? 2024-??-??   2023-11-28 2023-11-28
+## 2  -6 NYT 2024        0       NA 2024-01-01 2024-01-01   2023-11-27 2023-11-27
+## 3  -5 NYT 2023        1       96 2023-01-01 2023-01-01   2022-11-22 2022-11-22
+## 4  -4   CoC II        1       87 2022-06-23 2022-06-23   2021-09-15 2021-09-15
+## 5  -3 NYT 2022        1       73 2022-01-01 2022-01-01         <NA>       <NA>
+## 6  -2 NYT 2021        1       62 2021-01-01 2021-01-01         <NA>       <NA>
+## 7  -1      CoC        2       29 2017-12-13 2017-12-20   2017-11-20 2017-11-20
+## 8   1 Series 1        6        4 2015-07-28 2015-09-01   2015-03-23 2015-03-25
+## 9   2 Series 2        5       11 2016-06-21 2016-07-19         <NA>       <NA>
+## 10  3 Series 3        5       16 2016-10-04 2016-11-01         <NA>       <NA>
+##    points tasks special TMI
+## 1      NA    NA       1  88
+## 2      NA    NA       1  87
+## 3      76     5       1  66
+## 4      66     5       1  46
+## 5      68     5       1  47
+## 6      62     5       1  12
+## 7     164    10       1   6
+## 8     436    32       0   1
+## 9     417    28       0   2
+## 10    386    27       0   3
+

Advanced query

+

A more involved query involving JOIN and date manipulation

+
# A join, and data manipulation
+query <- "SELECT ts.name,
+ts.special as special_flag,
+tp.name as champion_name,
+tp.seat as chamption_seat,
+DATE(ts.studio_end) as studio_end, 
+DATE(ts.air_start) as air_start, 
+JULIANDAY(ts.air_start) - JULIANDAY(ts.studio_end) as broadcast_lag_days
+FROM series ts
+LEFT JOIN people tp
+ON ts.id = tp.series
+AND ts.champion = tp.id
+WHERE ts.special <> 1
+"
+
+results <- dbGetQuery(tm_db, query)
+results
+
##         name special_flag    champion_name chamption_seat studio_end  air_start
+## 1   Series 1            0  Josh Widdicombe              2 2015-03-25 2015-07-28
+## 2   Series 2            0   Katherine Ryan              4       <NA> 2016-06-21
+## 3   Series 3            0      Rob Beckett              4       <NA> 2016-10-04
+## 4   Series 4            0    Noel Fielding              5       <NA> 2017-04-25
+## 5   Series 5            0     Bob Mortimer              2 2017-07-06 2017-09-13
+## 6   Series 6            0     Liza Tarbuck              3 2018-03-28 2018-05-02
+## 7   Series 7            0   Kerry Godliman              3 2018-07-25 2018-09-05
+## 8   Series 8            0      Lou Sanders              3 2019-03-27 2019-05-08
+## 9   Series 9            0        Ed Gamble              2 2019-07-24 2019-09-04
+## 10 Series 10            0  Richard Herring              5 2020-07-29 2020-10-15
+## 11 Series 11            0    Sarah Kendall              5       <NA> 2021-03-18
+## 12 Series 12            0 Morgana Robinson              4       <NA> 2021-09-23
+## 13 Series 13            0     Sophie Duker              5 2021-09-22 2022-04-14
+## 14 Series 14            0    Dara Ó Briain              1 2022-05-05 2022-09-29
+## 15 Series 15            0       Mae Martin              5 2022-09-28 2023-03-30
+## 16 Series 16            0     Sam Campbell              3 2023-05-12 2023-09-21
+##    broadcast_lag_days
+## 1                 125
+## 2                  NA
+## 3                  NA
+## 4                  NA
+## 5                  69
+## 6                  35
+## 7                  42
+## 8                  42
+## 9                  42
+## 10                 78
+## 11                 NA
+## 12                 NA
+## 13                204
+## 14                147
+## 15                183
+## 16                132
+

The results of this query already indicate interesting insights, namely that 204 days (approximately 29 weeks) occurred between the studio record and first air date for Series 13, which is a noticeable deviation from prior seasons (greater broadcast lag). Future series also seem delayed, although to a lesser extent. Could the pandemic have initiated this lag? Or where there other production changes that led to this lag?

+

Times Up!

+

And that concludes this task! Hopefully you’ve been able to connect to the TdlM database directly through R and potentially inspired to start performing your own analysis.

+ +
+ + +
+
+ +
+ + diff --git a/public/tags/beginner/index.html b/public/tags/beginner/index.html new file mode 100644 index 0000000..925fc4d --- /dev/null +++ b/public/tags/beginner/index.html @@ -0,0 +1,94 @@ + + + + Beginner - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "Beginner"

+ + + + +
+ + diff --git a/public/tags/beginner/index.xml b/public/tags/beginner/index.xml new file mode 100644 index 0000000..2f9d0c5 --- /dev/null +++ b/public/tags/beginner/index.xml @@ -0,0 +1,20 @@ + + + + Beginner on The Median Duck + //localhost:4321/tags/beginner/ + Recent content in Beginner on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! This article provides an overview of Trabajo de las Mesas, a pivotal database that will be central to this project. The article will also provide guidance on how to connect to the database from within R. Trabajo de las Mesas Database Trabajo de las Mesas (TdlM 1) provides a plethora of data associated with Taskmaster in a database format. + + + diff --git a/public/tags/data/index.html b/public/tags/data/index.html new file mode 100644 index 0000000..28d4079 --- /dev/null +++ b/public/tags/data/index.html @@ -0,0 +1,94 @@ + + + + Data - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "data"

+ + + + +
+ + diff --git a/public/tags/data/index.xml b/public/tags/data/index.xml new file mode 100644 index 0000000..3368ccf --- /dev/null +++ b/public/tags/data/index.xml @@ -0,0 +1,20 @@ + + + + Data on The Median Duck + http://localhost:4321/themedianduck/tags/data/ + Recent content in Data on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 31 Jul 2024 00:00:00 +0000 + + + Sidenote: Musings on TdlM + http://localhost:4321/themedianduck/2024/07/31/data-quality-musings/ + Wed, 31 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/2024/07/31/data-quality-musings/ + Sidenote Introduction A few remarks and musings on TdlM Data Quality As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster. + + + diff --git a/public/tags/getting-started/index.html b/public/tags/getting-started/index.html new file mode 100644 index 0000000..26e7b7e --- /dev/null +++ b/public/tags/getting-started/index.html @@ -0,0 +1,86 @@ + + + + Getting Started - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "Getting Started"

+ + + + +
+ + diff --git a/public/tags/getting-started/index.xml b/public/tags/getting-started/index.xml new file mode 100644 index 0000000..edabe51 --- /dev/null +++ b/public/tags/getting-started/index.xml @@ -0,0 +1,20 @@ + + + + Getting Started on The Median Duck + http://localhost:4321/themedianduck/tags/getting-started/ + Recent content in Getting Started on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/tags/hugo_test/index.html b/public/tags/hugo_test/index.html new file mode 100644 index 0000000..c726ec7 --- /dev/null +++ b/public/tags/hugo_test/index.html @@ -0,0 +1,94 @@ + + + + Hugo_test - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "hugo_test"

+ + + + +
+ + diff --git a/public/tags/hugo_test/index.xml b/public/tags/hugo_test/index.xml new file mode 100644 index 0000000..ab6ad60 --- /dev/null +++ b/public/tags/hugo_test/index.xml @@ -0,0 +1,20 @@ + + + + Hugo_test on The Median Duck + //localhost:4321/tags/hugo_test/ + Recent content in Hugo_test on The Median Duck + Hugo + en-us + © Christopher Nam + Sat, 06 Jul 2024 00:00:00 +0000 + + + New Post on Archie + //localhost:4321/2024/07/new-post-on-archie/ + Sat, 06 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/new-post-on-archie/ + Intro This is my first post in the Archie template in hugo. Here&rsquo;s a random sample from the standard Normal distribution. rnorm(5) ## [1] -0.3637057 -0.4214060 0.6501004 -0.8329920 1.3021409 Here&rsquo;s an image of a duck. Did I create a html from this? + + + diff --git a/public/tags/index.html b/public/tags/index.html new file mode 100644 index 0000000..033b4d0 --- /dev/null +++ b/public/tags/index.html @@ -0,0 +1,149 @@ + + + + Tags - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +

All tags

+ + + + + + + + +
+ +
+ +
+ + diff --git a/public/tags/index.xml b/public/tags/index.xml new file mode 100644 index 0000000..8168efa --- /dev/null +++ b/public/tags/index.xml @@ -0,0 +1,97 @@ + + + + Tags on The Median Duck + //localhost:4321/tags/ + Recent content in Tags on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 17 Jul 2024 00:00:00 +0000 + + + Musings + //localhost:4321/tags/musings/ + Wed, 17 Jul 2024 00:00:00 +0000 + //localhost:4321/tags/musings/ + + + + TdlM + //localhost:4321/tags/tdlm/ + Wed, 17 Jul 2024 00:00:00 +0000 + //localhost:4321/tags/tdlm/ + + + + Beginner + //localhost:4321/tags/beginner/ + Wed, 10 Jul 2024 00:00:00 +0000 + //localhost:4321/tags/beginner/ + + + + Strength in Data + //localhost:4321/tags/strength-in-data/ + Wed, 10 Jul 2024 00:00:00 +0000 + //localhost:4321/tags/strength-in-data/ + + + + Hugo_test + //localhost:4321/tags/hugo_test/ + Sat, 06 Jul 2024 00:00:00 +0000 + //localhost:4321/tags/hugo_test/ + + + + Plot + //localhost:4321/tags/plot/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/tags/plot/ + + + + R Markdown + //localhost:4321/tags/r-markdown/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/tags/r-markdown/ + + + + Regression + //localhost:4321/tags/regression/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/tags/regression/ + + + + Primer + //localhost:4321/tags/primer/ + Wed, 01 Apr 2020 02:01:58 +0530 + //localhost:4321/tags/primer/ + + + + Todo + //localhost:4321/tags/todo/ + Wed, 01 Apr 2020 02:01:58 +0530 + //localhost:4321/tags/todo/ + + + + Procrastinating + //localhost:4321/tags/procrastinating/ + Sun, 18 Mar 2018 12:13:32 +0530 + //localhost:4321/tags/procrastinating/ + + + + Space + //localhost:4321/tags/space/ + Sun, 18 Mar 2018 12:13:30 +0530 + //localhost:4321/tags/space/ + + + + diff --git a/public/tags/intro/index.html b/public/tags/intro/index.html new file mode 100644 index 0000000..1ea9dcb --- /dev/null +++ b/public/tags/intro/index.html @@ -0,0 +1,83 @@ + + + + Intro - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +

Entries tagged - "Intro"

+ + + + +
+ + diff --git a/public/tags/intro/index.xml b/public/tags/intro/index.xml new file mode 100644 index 0000000..7f18efc --- /dev/null +++ b/public/tags/intro/index.xml @@ -0,0 +1,20 @@ + + + + Intro on The Median Duck + http://localhost:4321/themedianduck/tags/intro/ + Recent content in Intro on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/post/2024-07-10-strength-in-data-connecting-to-the-taskmaster-database/ + + + + diff --git a/public/tags/introduction/index.html b/public/tags/introduction/index.html new file mode 100644 index 0000000..5ea9b44 --- /dev/null +++ b/public/tags/introduction/index.html @@ -0,0 +1,86 @@ + + + + Introduction - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "Introduction"

+ + + + +
+ + diff --git a/public/tags/introduction/index.xml b/public/tags/introduction/index.xml new file mode 100644 index 0000000..f78e879 --- /dev/null +++ b/public/tags/introduction/index.xml @@ -0,0 +1,20 @@ + + + + Introduction on The Median Duck + http://localhost:4321/themedianduck/tags/introduction/ + Recent content in Introduction on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/tags/musings/index.html b/public/tags/musings/index.html new file mode 100644 index 0000000..26c1b8f --- /dev/null +++ b/public/tags/musings/index.html @@ -0,0 +1,94 @@ + + + + Musings - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "Musings"

+ + + + +
+ + diff --git a/public/tags/musings/index.xml b/public/tags/musings/index.xml new file mode 100644 index 0000000..0bc1585 --- /dev/null +++ b/public/tags/musings/index.xml @@ -0,0 +1,20 @@ + + + + Musings on The Median Duck + //localhost:4321/tags/musings/ + Recent content in Musings on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 17 Jul 2024 00:00:00 +0000 + + + Sidenote: Musings on TdlM + //localhost:4321/2024/07/data-quality-musings/ + Wed, 17 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/data-quality-musings/ + Sidenote Introduction Data Quality Why This Datasource? Potential Articles to Explore in the Future Sidenote Introduction A few remarks and musings on the Trabajo de las Mesas database (TdlM). Data Quality As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster. + + + diff --git a/public/tags/plot/index.html b/public/tags/plot/index.html new file mode 100644 index 0000000..dad718e --- /dev/null +++ b/public/tags/plot/index.html @@ -0,0 +1,94 @@ + + + + Plot - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "plot"

+ + + + +
+ + diff --git a/public/tags/plot/index.xml b/public/tags/plot/index.xml new file mode 100644 index 0000000..0fe9daa --- /dev/null +++ b/public/tags/plot/index.xml @@ -0,0 +1,20 @@ + + + + Plot on The Median Duck + //localhost:4321/tags/plot/ + Recent content in Plot on The Median Duck + Hugo + en-us + © Christopher Nam + Tue, 01 Dec 2020 21:13:14 -0500 + + + Hello R Markdown + //localhost:4321/2020/12/hello-r-markdown/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/2020/12/hello-r-markdown/ + R Markdown This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com. You can embed an R code chunk like this: summary(cars) ## speed dist ## Min. : 4.0 Min. : 2.00 ## 1st Qu.:12.0 1st Qu.: 26.00 ## Median :15.0 Median : 36.00 ## Mean :15.4 Mean : 42.98 ## 3rd Qu. + + + diff --git a/public/tags/primer/index.html b/public/tags/primer/index.html new file mode 100644 index 0000000..594d796 --- /dev/null +++ b/public/tags/primer/index.html @@ -0,0 +1,94 @@ + + + + Primer - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "Primer"

+ + + + +
+ + diff --git a/public/tags/primer/index.xml b/public/tags/primer/index.xml new file mode 100644 index 0000000..50aac29 --- /dev/null +++ b/public/tags/primer/index.xml @@ -0,0 +1,20 @@ + + + + Primer on The Median Duck + //localhost:4321/tags/primer/ + Recent content in Primer on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 01 Apr 2020 02:01:58 +0530 + + + Primer: When You Have Too Much to Do + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + Wed, 01 Apr 2020 02:01:58 +0530 + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more. It all keeps piling up, and it can feel overwhelming. How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate? + + + diff --git a/public/tags/procrastinating/index.html b/public/tags/procrastinating/index.html new file mode 100644 index 0000000..5a7cfd5 --- /dev/null +++ b/public/tags/procrastinating/index.html @@ -0,0 +1,94 @@ + + + + Procrastinating - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "Procrastinating"

+ + + + +
+ + diff --git a/public/tags/procrastinating/index.xml b/public/tags/procrastinating/index.xml new file mode 100644 index 0000000..4e3d4e4 --- /dev/null +++ b/public/tags/procrastinating/index.xml @@ -0,0 +1,20 @@ + + + + Procrastinating on The Median Duck + //localhost:4321/tags/procrastinating/ + Recent content in Procrastinating on The Median Duck + Hugo + en-us + © Christopher Nam + Sun, 18 Mar 2018 12:13:32 +0530 + + + How I Learned to Stop Procrastinating, & Love Letting Go + //localhost:4321/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/ + Sun, 18 Mar 2018 12:13:32 +0530 + //localhost:4321/2018/03/how-i-learned-to-stop-procrastinating-love-letting-go/ + The end of procrastination is the art of letting go. I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done. Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. + + + diff --git a/public/tags/r-markdown/index.html b/public/tags/r-markdown/index.html new file mode 100644 index 0000000..b64ad64 --- /dev/null +++ b/public/tags/r-markdown/index.html @@ -0,0 +1,94 @@ + + + + R Markdown - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "R Markdown"

+ + + + +
+ + diff --git a/public/tags/r-markdown/index.xml b/public/tags/r-markdown/index.xml new file mode 100644 index 0000000..6f50348 --- /dev/null +++ b/public/tags/r-markdown/index.xml @@ -0,0 +1,20 @@ + + + + R Markdown on The Median Duck + //localhost:4321/tags/r-markdown/ + Recent content in R Markdown on The Median Duck + Hugo + en-us + © Christopher Nam + Tue, 01 Dec 2020 21:13:14 -0500 + + + Hello R Markdown + //localhost:4321/2020/12/hello-r-markdown/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/2020/12/hello-r-markdown/ + R Markdown This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com. You can embed an R code chunk like this: summary(cars) ## speed dist ## Min. : 4.0 Min. : 2.00 ## 1st Qu.:12.0 1st Qu.: 26.00 ## Median :15.0 Median : 36.00 ## Mean :15.4 Mean : 42.98 ## 3rd Qu. + + + diff --git a/public/tags/regression/index.html b/public/tags/regression/index.html new file mode 100644 index 0000000..139cc0c --- /dev/null +++ b/public/tags/regression/index.html @@ -0,0 +1,94 @@ + + + + Regression - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "regression"

+ + + + +
+ + diff --git a/public/tags/regression/index.xml b/public/tags/regression/index.xml new file mode 100644 index 0000000..30a98ec --- /dev/null +++ b/public/tags/regression/index.xml @@ -0,0 +1,20 @@ + + + + Regression on The Median Duck + //localhost:4321/tags/regression/ + Recent content in Regression on The Median Duck + Hugo + en-us + © Christopher Nam + Tue, 01 Dec 2020 21:13:14 -0500 + + + Hello R Markdown + //localhost:4321/2020/12/hello-r-markdown/ + Tue, 01 Dec 2020 21:13:14 -0500 + //localhost:4321/2020/12/hello-r-markdown/ + R Markdown This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com. You can embed an R code chunk like this: summary(cars) ## speed dist ## Min. : 4.0 Min. : 2.00 ## 1st Qu.:12.0 1st Qu.: 26.00 ## Median :15.0 Median : 36.00 ## Mean :15.4 Mean : 42.98 ## 3rd Qu. + + + diff --git a/public/tags/setup/index.html b/public/tags/setup/index.html new file mode 100644 index 0000000..c57f17f --- /dev/null +++ b/public/tags/setup/index.html @@ -0,0 +1,86 @@ + + + + Setup - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ +

Entries tagged - "Setup"

+ + + + +
+ + diff --git a/public/tags/setup/index.xml b/public/tags/setup/index.xml new file mode 100644 index 0000000..cfa759e --- /dev/null +++ b/public/tags/setup/index.xml @@ -0,0 +1,20 @@ + + + + Setup on The Median Duck + http://localhost:4321/themedianduck/tags/setup/ + Recent content in Setup on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + http://localhost:4321/themedianduck/posts/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! Introduction and Objective This article provides an overview of Trabajo de las Mesas, a pivotal Taskmaster database that will be central to performing a multitude of analysis and questions that we may want to answer regarding Taskmaster. TOC The article will also provide guidance on how to connect to the database from within . + + + diff --git a/public/tags/space/index.html b/public/tags/space/index.html new file mode 100644 index 0000000..a19bdc3 --- /dev/null +++ b/public/tags/space/index.html @@ -0,0 +1,94 @@ + + + + Space - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "Space"

+ + + + +
+ + diff --git a/public/tags/space/index.xml b/public/tags/space/index.xml new file mode 100644 index 0000000..ea3831d --- /dev/null +++ b/public/tags/space/index.xml @@ -0,0 +1,20 @@ + + + + Space on The Median Duck + //localhost:4321/tags/space/ + Recent content in Space on The Median Duck + Hugo + en-us + © Christopher Nam + Sun, 18 Mar 2018 12:13:30 +0530 + + + Fearlessness: How to Stop Running from Space + //localhost:4321/2018/03/fearlessness-how-to-stop-running-from-space/ + Sun, 18 Mar 2018 12:13:30 +0530 + //localhost:4321/2018/03/fearlessness-how-to-stop-running-from-space/ + We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos. We are afraid of empty space in our lives. The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives. We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. + + + diff --git a/public/tags/strength-in-data/index.html b/public/tags/strength-in-data/index.html new file mode 100644 index 0000000..b1df268 --- /dev/null +++ b/public/tags/strength-in-data/index.html @@ -0,0 +1,94 @@ + + + + Strength in Data - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "Strength in Data"

+ + + + +
+ + diff --git a/public/tags/strength-in-data/index.xml b/public/tags/strength-in-data/index.xml new file mode 100644 index 0000000..203444d --- /dev/null +++ b/public/tags/strength-in-data/index.xml @@ -0,0 +1,20 @@ + + + + Strength in Data on The Median Duck + //localhost:4321/tags/strength-in-data/ + Recent content in Strength in Data on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 10 Jul 2024 00:00:00 +0000 + + + Strength in Data: Connecting to the Taskmaster Database + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Wed, 10 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/strength-in-data-connecting-to-the-taskmaster-database/ + Your Task Successfully connect to the Taskmaster database from within R. Fastest wins; your time starts now! This article provides an overview of Trabajo de las Mesas, a pivotal database that will be central to this project. The article will also provide guidance on how to connect to the database from within R. Trabajo de las Mesas Database Trabajo de las Mesas (TdlM 1) provides a plethora of data associated with Taskmaster in a database format. + + + diff --git a/public/tags/tdlm/index.html b/public/tags/tdlm/index.html new file mode 100644 index 0000000..c3085c2 --- /dev/null +++ b/public/tags/tdlm/index.html @@ -0,0 +1,94 @@ + + + + TdlM - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "TdlM"

+ + + + +
+ + diff --git a/public/tags/tdlm/index.xml b/public/tags/tdlm/index.xml new file mode 100644 index 0000000..080527a --- /dev/null +++ b/public/tags/tdlm/index.xml @@ -0,0 +1,20 @@ + + + + TdlM on The Median Duck + //localhost:4321/tags/tdlm/ + Recent content in TdlM on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 17 Jul 2024 00:00:00 +0000 + + + Sidenote: Musings on TdlM + //localhost:4321/2024/07/data-quality-musings/ + Wed, 17 Jul 2024 00:00:00 +0000 + //localhost:4321/2024/07/data-quality-musings/ + Sidenote Introduction Data Quality Why This Datasource? Potential Articles to Explore in the Future Sidenote Introduction A few remarks and musings on the Trabajo de las Mesas database (TdlM). Data Quality As with any analysis and modelling project, the insights and conclusions generated are only as good as the data supplied to it. I do not know the specifics regarding how this data is collated and reviewed (my intention is that there will be a future article dedicated to this), but believe the data is inputted by fellow (hardcore) Taskmaster fans from taskmaster. + + + diff --git a/public/tags/todo/index.html b/public/tags/todo/index.html new file mode 100644 index 0000000..e6323d9 --- /dev/null +++ b/public/tags/todo/index.html @@ -0,0 +1,94 @@ + + + + Todo - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + + +

Entries tagged - "todo"

+ + + + +
+ + diff --git a/public/tags/todo/index.xml b/public/tags/todo/index.xml new file mode 100644 index 0000000..e612ae5 --- /dev/null +++ b/public/tags/todo/index.xml @@ -0,0 +1,20 @@ + + + + Todo on The Median Duck + //localhost:4321/tags/todo/ + Recent content in Todo on The Median Duck + Hugo + en-us + © Christopher Nam + Wed, 01 Apr 2020 02:01:58 +0530 + + + Primer: When You Have Too Much to Do + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + Wed, 01 Apr 2020 02:01:58 +0530 + //localhost:4321/2020/04/primer-when-you-have-too-much-to-do/ + You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more. It all keeps piling up, and it can feel overwhelming. How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate? + + + diff --git a/public/tasks.Rmd b/public/tasks.Rmd new file mode 100644 index 0000000..af514e0 --- /dev/null +++ b/public/tasks.Rmd @@ -0,0 +1,55 @@ +--- +title: Your Time Starts Now! +date: 2024-07-17 +draft: false +--- + +A site about Taskmaster has got to have some tasks....surely? + + +# The Prize Task + +This project is self initiated and funded. If you +would like to show your appreciation and gratitude in this project, feel +free to donate to my [buy me a coffee +page](https://buymeacoffee.com/bluevolvo87). All donations are welcome. + +> Make a donation to the aforementioned [Buy Me a Coffee +> page](https://buymeacoffee.com/bluevolvo87). The Median Donation +> Amount for the calendar month wins! + +------------------------------------------------------------------------ + +# The Individual Task + +In order to achieve the desired vision, multiple contributors would be +appreciated; as of `r Sys.Date()` it is just myself. The first step in +the road to this vision is to tell as many people about this project. + +> Tell and redirect as many people as you can about The Median Duck +> project. Most number of redirects for the calendar months wins! + +------------------------------------------------------------------------ + +# The Team Task + +There are no doubt teething errors and mistakes in this project; +constructive feedback and criticism is welcome! + +> Provide constructive criticism on the project by sending an e-mail to +> [themedianduck\@gmail.com](mailto:themedianduck@gmail.com){.email}. +> Most useful constructive criticism provided wins. Your time starts +> now! + +------------------------------------------------------------------------ + +# The Team Studio Task + +Based on the ambitious [vision](vision) of this project, and my limited skillset +and bandwidth, contributors are also welcome in any shape or form +(website design, article writing, analysis expertise)! + +> Contribute to The Median Duck project; best contribution wins. E-mail +> [themedianduck\@gmail.com](mailto:themedianduck@gmail.com){.email} to +> express your contribution interest. Most useful contribution provided +> wins. Your time starts now! diff --git a/public/tasks/index.html b/public/tasks/index.html new file mode 100644 index 0000000..1e83b40 --- /dev/null +++ b/public/tasks/index.html @@ -0,0 +1,172 @@ + + + + Your Time Starts Now! - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

Your Time Starts Now!

+
Posted on Jul 17, 2024
+
+ + +
+ +
+ +
+ + + +

A site about Taskmaster has got to have some tasks….surely?

+
+

The Prize Task

+

This project is self initiated and funded. If you +would like to show your appreciation and gratitude in this project, feel +free to donate to my buy me a coffee +page. All donations are welcome.

+
+

Make a donation to the aforementioned Buy Me a Coffee +page. The Median Donation +Amount for the calendar month wins!

+
+
+
+
+

The Individual Task

+

In order to achieve the desired vision, multiple contributors would be +appreciated; as of 2024-08-06 it is just myself. The first step in +the road to this vision is to tell as many people about this project.

+
+

Tell and redirect as many people as you can about The Median Duck +project. Most number of redirects for the calendar months wins!

+
+
+
+
+

The Team Task

+

There are no doubt teething errors and mistakes in this project; +constructive feedback and criticism is welcome!

+
+

Provide constructive criticism on the project by sending an e-mail to +. +Most useful constructive criticism provided wins. Your time starts +now!

+
+
+
+
+

The Team Studio Task

+

Based on the ambitious vision of this project, and my limited skillset +and bandwidth, contributors are also welcome in any shape or form +(website design, article writing, analysis expertise)!

+
+

Contribute to The Median Duck project; best contribution wins. E-mail + to +express your contribution interest. Most useful contribution provided +wins. Your time starts now!

+
+
+ +
+ + + + +
+
+ +
+ + diff --git a/public/telegram-bot-for-github-actions/index.html b/public/telegram-bot-for-github-actions/index.html new file mode 100644 index 0000000..20aff6a --- /dev/null +++ b/public/telegram-bot-for-github-actions/index.html @@ -0,0 +1,439 @@ + + + + Telegram Bot for GitHub Actions - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Telegram Bot for GitHub Actions

+
Posted on 2020-04-01 DRAFT
+
+ +
+ tl;dr: + Making GitHub Actions with Js Code +
+ +
+

Telegram

+

Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API.

+

GitHub Actions

+

GitHub Actions is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. You can build, test and deploy your code with GitHub Actions. All these actions are called workflows and workflows differ in the job they’re doing. These maybe test workflows, build ones or deployment ones. You can find all the actions on GitHub in the marketplace

+

Building the Bot

+

Prerequisites

+
    +
  • Basic JavaScript Knowledge
  • +
  • Basic GitHub Knowledge
  • +
  • Telegram Account
  • +
+
+

There are templates for building actions. Here we’re gonna start from scratch

+
+

Environment Setup

+
    +
  • Node, You can download node from their website
  • +
  • NPM comes with node, so you don’t have to worry about it.
  • +
  • Initialize the Project
  • +
+
$ git init ## initialize a new git repository for version management
+---
+$ npm init
+
    +
  • dotenv, Dotenv can be downloaded via
  • +
+
$ npm i dotenv
+---
+$ yarn add dotenv
+
    +
  • node-telegram-bot-api, node-telegram-bot-api is a simple wrapper for building telegram bots. You can download it via
  • +
+
$ npm i node-telegram-bot-api
+---
+$ yarn add node-telegram-bot-api
+
    +
  • @zeit/ncc, NCC is a Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, GCC-style. It’s a dev dependency and can be downloaded
  • +
+
yarn add --dev @zeit/ncc
+---
+npm i -D @zeit/ncc
+

Folder Structure

+

The dist folder will be automatically created. action.yml will be made

+
.
+├── dist
+│   └── index.js
+├── index.js
+├── action.yml
+├── README.md
+└── package.json
+
    +
  • index.js is the file we’re defining the bot
  • +
  • action.yml is the file we’ll define the action and it’s behaviours
  • +
+

Making the Bot

+

We need to get an API bot token from telegram. For that Go to Telegram and Search for Botfather. It’s a bot. + +Create a new bot with the /newbot command and get the API key. We’ll need that, also talk to jsondump bot and get your chat id. The output may be like this, so

+
{
+  "update_id": 143943779,
+  "message": {
+    "message_id": 181575,
+    "from": {
+      "id": 123456 // this is what we need
+      "is_bot": false,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "language_code": "en"
+    },
+    "chat": {
+      "id": 123456,
+      "first_name": "Tg Name",
+      "username": "TG Username",
+      "type": "private"
+    },
+    "date": 1584119424,
+    "text": "message"
+  }
+}
+

This will be needed for further use and We need to add it to the repo secrets which can be found in the repo settings. Be careful to add it as token and chat like as shown below +

+

Writing the Action and Building the Bot

+

Fire up the terminal/cmd and make a new folder. Install the dependencies. Run the following command

+
$ touch index.js action.yml
+

Open your favourite text editor within the folder or with the file. We’ll define the bot in index.js

+
require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+const {
+    INPUT_STATUS: ipstatus,
+    INPUT_TOKEN: tgtoken,//Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor,// Issue made by
+    INPUT_IU_BODY: ibody,// Issue Body
+    INPUT_PR_NUM: pnum,// PR Number
+    INPUT_PR_STATE: prstate,// PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle,// PR Title
+    INPUT_PR_BODY: pbody,// Body of the PR
+    GITHUB_EVENT_NAME: ghevent,// Name of the trigger event
+    GITHUB_REPOSITORY: repo,// Repository the trigger was made from
+    GITHUB_ACTOR: ghactor,// User who triggered the action
+    GITHUB_SHA: sha,// Commit ID
+    GITHUB_WORKFLOW: ghwrkflw// Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+

First, we’re defining the dotenv for config and initializing Telegram Bot. Here we’re defining the alias variables for the environment variables. You might notice an INPUT_ for almost every environment variable, this is because GitHub Actions pass the env variable with an INPUT prefix. Other env variables are action’s default environment variables. Then we initialized the bot with the API token.

+

GitHub actions could be triggered with Issues, Pull Request or Pushes. You can find the trigger events here. Here we’re gonna get a message from the bot when an Issue or Pull Request or a Push event has happened.

+
const evresp = (gevent) => {
+    switch (gevent) {
+
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+

In these lines of code, we’re just initializing a switch statement for the responses. We’re also declaring an anonymous function to use the switch responses via a function later. We’re using all the defined variables in the switch. You can check the trigger Events to get how the event is triggered and what keyword should be used.

+

Now for the last part of the Js file, we just take the response from the switch and assign it to a constant. Then we use the sendMessage function of the node-telegram-bot-api to send the message to the bot with the chatid and the output as the arguments.

+
const output = evresp(ghevent)
+

bot.sendMessage(chatid,output,{parse_mode : “Markdown”})

+

Compiling and Minifying the Js code

+

Since we have installed @zeit/ncc and this is used for the making the whole program with all the APIs to a single file and we need to use NCC for that. We just need to run

+
yarn run ncc build index.js -C -m -o dist
+

or you might wanna add the following to you package.json file, and run npm run test to compile and minify the code.

+
"scripts": {
+    "test": "ncc build index.js -C -m -o dist"
+  },
+

This will create a dist folder with and index.js file which contains the compiled code.

+

Making it a valid action

+

For making this Js file a valid action, we need to add an action.yml file. The action.yml for this action is like this

+
name: 'Action Name'
+description: 'Action Descreption'
+author: '<author name>'
+inputs: 
+  chat:
+    description: 'Chat to send: chat id or @channel_name'
+    required: true
+  token:
+    description: 'Telegram Bot token'
+    required: true
+  status:
+    description: 'Job status'
+    required: true
+  iu_title: 
+    description: 'Issue Title'
+    default: ${{ github.event.issue.title }}
+  iu_num:
+    description: 'Issue Number'
+    default: ${{ github.event.issue.number }}
+  iu_actor: 
+    description: 'Issue Triggerer'
+    default: ${{ github.event.issue.user.login }}
+  iu_com:
+    description: 'Issue Comment'
+    default: ${{github.event.comment.body}}
+  pr_state:
+    description: 'State of the PR'
+    default: ${{ github.event.action }}
+  pr_num:
+    description: 'PR Number'
+    default: ${{ github.event.number }}
+  pr_title:
+    description: 'Title of the PR'
+    default: ${{ github.event.pull_request.title }}
+  pr_body:
+    description: 'Body/Contents of the PR'
+    default: ${{ github.event.pull_request.body }}
+runs:
+  using: "node12"
+  main: "dist/index.js"
+branding:
+  icon: 'repeat'  
+  color: 'green'
+

Here we’re defining the Input variables to be loaded for the action in GitHub’s runtime environemt. All these default data are taken from the response of the webhooks which are send by GitHub when a trigger event is occured. You can find out more in the Action Documentation Here.

+
runs:
+  using: "node12"
+  main: "dist/index.js"
+

Here we are defining that this is a node action and should run in an environment with node, and the file which should be run, here the index.js file in the dist folder. That should do it. Create a new commit and push it to a repo. Create a new tag and this action will appear in the marketplace.

+

Defining a workflow to test your action

+

GitHub Action workflows are defined using the .yml syntax. Here is an example of a sample workflow for this action

+
name: <Workflow Name>
+
+on:
+  push:
+  pull_request:
+    types: [opened, closed]
+  issues:
+    types: [opened, closed, reopened]
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: <AnyName>
+        uses: <username>/<repo>@master
+        if: always()
+        with:
+          chat: ${{ secrets.chat }}
+          token: ${{ secrets.token }}
+          status: ${{ job.status }}
+

The Complete code for the bot is

+
//Initializing dotenv and the bot
+require("dotenv").config
+const Bot = require('node-telegram-bot-api');
+// aliasing the environment variables 
+const {
+    INPUT_STATUS: ipstatus, 
+    INPUT_TOKEN: tgtoken, //Telegram api token
+    INPUT_CHAT: chatid,// Telegram Chat ID
+    INPUT_IU_TITLE: ititle,// Issue title
+    INPUT_IU_NUM: inum,// Issue Number
+    INPUT_IU_ACTOR: iactor, // Issue made by
+    INPUT_IU_BODY: ibody, // Issue Body
+    INPUT_PR_NUM: pnum, // PR Number
+    INPUT_PR_STATE: prstate, // PR Opened, reponed or closed
+    INPUT_PR_TITLE: ptitle, // PR Title
+    INPUT_PR_BODY: pbody, // Body of the PR
+    GITHUB_EVENT_NAME: ghevent, // Name of the trigger event
+    GITHUB_REPOSITORY: repo, // Repository the trigger was made from
+    GITHUB_ACTOR: ghactor, // User who triggered the action
+    GITHUB_SHA: sha, // Commit ID
+    GITHUB_WORKFLOW: ghwrkflw // Workflow Name
+} = process.env;
+
+const bot = new Bot(tgtoken)
+// Function to return the response for the specific trigger
+const evresp = (gevent) => {
+    switch (gevent) {
+//Switch statement for issues
+        case "issues":
+            return `
+❗️❗️❗️❗️❗️❗️
+        
+Issue ${prstate}
+
+Issue Title and Number  : ${ititle} | #${inum}
+
+Commented or Created By : \`${iactor}\`
+
+Issue Body : *${ibody}*
+
+[Link to Issue](https://github.com/${repo}/issues/${inum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+// Switch statement for Pull Requests
+        case "pull_request":
+            return `
+🔃🔀🔃🔀🔃🔀
+PR ${prstate} 
+        
+PR Number:      ${pnum}
+        
+PR Title:       ${ptitle}
+        
+PR Body:        *${pbody}*
+        
+PR By:          ${ghactor}
+        
+[Link to Issue](https://github.com/${repo}/pull/${pnum})
+[Link to Repo ](https://github.com/${repo}/)
+[Build log here](https://github.com/${repo}/commit/${sha}/checks)`
+        default:
+// switch statement for Pushes
+            return `
+⬆️⇅⬆️⇅
+            
+ID: ${ghwrkflw}
+        
+Action was a *${ipstatus}!*
+        
+\`Repository:  ${repo}\` 
+        
+On:          *${ghevent}*
+        
+By:            *${ghactor}* 
+        
+Tag:        ${process.env.GITHUB_REF}
+        
+[Link to Repo ](https://github.com/${repo}/)
+            `
+    }
+}
+// assigning the output to a variable
+const output = evresp(ghevent)
+// sending the message
+bot.sendMessage(chatid,output,{parse_mode : "Markdown"})
+

+

You can try out many different items using actions and this is just a sample action to get you started. Maybe sending Cat GIFs if the build succeded on the pull request or sending a welcome message to a first time contributor. You imagination is the limit😄 and Never Stop being ⚡️

+ +
+ + +
+
+ +
+ + diff --git a/public/typography/index.html b/public/typography/index.html new file mode 100644 index 0000000..d134114 --- /dev/null +++ b/public/typography/index.html @@ -0,0 +1,155 @@ + + + + Typography - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+
+
+
+

Typography

+
Posted on 2018-03-18 DRAFT
+
+ + +
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 1

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 2

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 3

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Heading 4

+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 5
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+
Heading 6
+

Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits.

+

Typography

+

Lid est laborum et dolorum fuga, This is an example inline link. Et harum quidem rerum facilis, This is bold and emphasis cumque nihilse impedit quo minus id quod amets untra dolor amet sad. While this is code block() and following is a pre tag

+
print 'this is pre tag'
+
+

Following is the syntax highlighted code block

+
func getCookie(name string, r interface{}) (*http.Cookie, error) {
+	rd := r.(*http.Request)
+	cookie, err := rd.Cookie(name)
+	if err != nil {
+		return nil, err
+	}
+	return cookie, nil
+}
+
+func setCookie(cookie *http.Cookie, w interface{}) error {
+	// Get write interface registered using `Acquire` method in handlers.
+	wr := w.(http.ResponseWriter)
+	http.SetCookie(wr, cookie)
+	return nil
+}
+

This is blockquote, Will make it better now

+
+

‘I want to do with you what spring does with the cherry trees.’ cited ~Pablo Neruda*

+
+
+

Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit

+
+

Unordered list

+
    +
  • Red
  • +
  • Green
  • +
  • Blue
  • +
+

Ordered list

+
    +
  1. Red
  2. +
  3. Green
  4. +
  5. Blue
  6. +
+ +
+ + +
+
+ +
+ + diff --git a/public/vision/index.html b/public/vision/index.html new file mode 100644 index 0000000..0e19b0b --- /dev/null +++ b/public/vision/index.html @@ -0,0 +1,177 @@ + + + + The Vision - The Median Duck + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +

vires in notitia

+ + +
+
+
+

The Vision

+
Posted on Jul 4, 2024
+
+ + + + +
+

The Mission Statement

+
+

To entertain and educate the general public of statistical and analytical concepts through data associated with the hit UK TV show “Taskmaster”.

+
+

The Objective

+

Using data from the UK hit TV show “Taskmaster”, The Median Duck aims to entertain and educate the general public of statistical and analytical concepts. Articles and analysis will be written for a non-technical audience predominantly.

+

Types of analysis and content fall under the following umbrellas with some examples.

+

The various datasets, code snippets and analysis will be open source on this git repo, such that others are able to reproduce it at their own pace, and contribute to the project.

+

Exploratory Analysis

+
+

Based on existing series and historical data, what insights can we gleam.

+
+

Examples:

+
    +
  • Do older contestants fair better on the show? Is there a correlation between series ranking and age of contestant?
  • +
  • Has Greg been harsher as the show has progressed along?
  • +
  • Was Sally Phillips better at creative tasks, than objective tasks on average?
  • +
  • Existing analysis that you have performed thus far would fall into this category.
  • +
+

Predictive Analysis

+
+

Based on existing series and historical data, can we make a prediction on an outcome. The outcome will be realised eventually, and we can compare our prediction to the observed outcome to see how (in)accurate we were.

+
+

Examples:

+
    +
  • Prior to a series starting, can we predict who is likely to win the series? What are the probabilities (odds) of each contestant winning?
  • +
  • As the series progresses and we start to see actual contestant performance, how do these odds change?
  • +
+

Hypothetical Analysis

+
+

Based on existing data, can we make a hypothesise as to what an outcome may be. The outcome will not be realised (or at least very low probability), and we thus can’t compare our hypothesised prediction to reality.

+
+

Examples:

+
    +
  • Would Katherine Ryan still have won her series if it was a 10 episode series, rather than 5 episodes?
  • +
  • What would be the outcome of a hypothetical series featuring Ed Gamble, Victoria Coren Mitchell, Nish Kumar, Josh Widdicombe and Sally Phillips?
  • +
+

Game Theory and Strategy

+
+

Based on existing literature, what is a optimal way to succeed in a task.

+
+

Examples:

+
    +
  • What is the optimal strategy in Series 13’s “Guess Shoe” task?
  • +
  • What is the optimal strategy in Series 4’s “Draw the median duck” task?
  • +
  • What is the optimal strategy in Series 13’s “Give Alex a high-five. The third-fastest high-fiver wins.” task?
  • +
+

Final Thoughts

+

This vision is ambitious and I’m not entirely sure if I can pull it all (or any) of it off. However, in the spirit of Taskmaster, I am willing to give it a try, and potentially make a fool out of myself as I succeed or fail.

+

I’m hoping that documenting this vision will also inspire others to contribute and collaborate on the project in the future.

+ +
+ + + + +
+
+ +
+ + diff --git a/static/data/taskmaster.db b/static/data/taskmaster.db new file mode 100644 index 0000000..ca1e739 Binary files /dev/null and b/static/data/taskmaster.db differ diff --git a/static/img/duck_tt.png b/static/img/duck_tt.png new file mode 100644 index 0000000..8acab4c Binary files /dev/null and b/static/img/duck_tt.png differ diff --git a/static/img/logo.jpg b/static/img/logo.jpg new file mode 100644 index 0000000..4c4dba5 Binary files /dev/null and b/static/img/logo.jpg differ diff --git a/themedianduck.Rproj b/themedianduck.Rproj new file mode 100644 index 0000000..c2083b1 --- /dev/null +++ b/themedianduck.Rproj @@ -0,0 +1,15 @@ +Version: 1.0 + +RestoreWorkspace: Default +SaveWorkspace: Default +AlwaysSaveHistory: Default + +EnableCodeIndexing: Yes +UseSpacesForTab: Yes +NumSpacesForTab: 4 +Encoding: UTF-8 + +RnwWeave: Sweave +LaTeX: pdfLaTeX + +BuildType: Website diff --git a/themes/archie/LICENSE b/themes/archie/LICENSE new file mode 100644 index 0000000..646ad35 --- /dev/null +++ b/themes/archie/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2020 ATHUL CYRIAC AJAY + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/themes/archie/README.md b/themes/archie/README.md new file mode 100644 index 0000000..ef3e4d6 --- /dev/null +++ b/themes/archie/README.md @@ -0,0 +1,134 @@ +# Archie - Hugo theme +Archie is a minimal and clean theme for hugo with a markdown-ish UI. + +Forked from [Ezhil Theme](https://github.com/vividvilla/ezhil) + +## Demo + +[Check the Demo](https://athul.github.io/archie/) hosted on GitHub Pages :smile: . You can find the source code to that in the `site` branch of this repository + +![](/images/theme.png) +![](/images/archie-dark.png) +## Feature +- Google Analytics Script +- Callouts +- Tags +- Auto Dark Mode(based on system theme) +- Dark/Light Mode toggle +- tl:dr; frontamatter +- Cache busting for CSS files +- Disqus Comments + +## Installation +In your Hugo website directory, create a new folder named theme and clone the repo +```bash +$ mkdir themes +$ cd themes +$ git clone https://github.com/athul/archie.git +``` +Edit the `config.toml` file with `theme="archie"` +For more information read the official [setup guide](https://gohugo.io/installation/) of Hugo. + +If you encounter any issues with Google Analytics, update Hugo to v0.125.0 or +later and make sure your using the latest version of the theme. + +## Writing Posts +Create a new `.md` file in the *content/posts* folder +```yml +--- +title: Title of the post +description: +date: +tldr: (optional) +draft: true/false (optional) +tags: [tag names] (optional) +--- +``` + +## Credits +Forked from [Ezhil Theme](https://github.com/vividvilla/ezhil) and Licensed under MIT License +Inspired by design of blog.jse.li + +---- + +## Config Options + +### Custom CSS +Custom CSS files can be included though the `customcss` config parameter. + +Note: CSS files should be placed under the `assets` directory e.g. `assets/css/first.css`. + +```toml +[params] + customcss = ["css/first.css", "css/second.css"] +``` + + +## Config of the Demo Site + +```toml +baseURL = "https://athul.github.io/archie/" +languageCode = "en-us" +title = "Archie" +theme="archie" +copyright = "© Athul" +# Code Highlight +pygmentsstyle = "monokai" +pygmentscodefences = true +pygmentscodefencesguesssyntax = true + +disqusShortname = "yourDisqusShortname" + +paginate=3 # articles per page + +[params] + mode="auto" # color-mode → light,dark,toggle or auto + useCDN=false # don't use CDNs for fonts and icons, instead serve them locally. + subtitle = "Minimal and Clean [blog theme for Hugo](https://github.com/athul/archie)" + mathjax = true # enable MathJax support + katex = true # enable KaTeX support + +# Social Tags + +[[params.social]] +name = "GitHub" +icon = "github" +url = "https://github.com/athul/archie" + +[[params.social]] +name = "Twitter" +icon = "twitter" +url = "https://twitter.com/athulcajay/" + +[[params.social]] +name = "GitLab" +icon = "gitlab" +url = "https://gitlab.com/athul/" + +# Main menu Items + +[[menu.main]] +name = "Home" +url = "/" +weight = 1 + +[[menu.main]] +name = "All posts" +url = "/posts" +weight = 2 + +[[menu.main]] +name = "About" +url = "/about" +weight = 3 + +[[menu.main]] +name = "Tags" +url = "/tags" +weight = 4 +``` +--- + +If you liked my work please consider supporting me on [BuymeACoffee](https://www.buymeacoffee.com/athulca) + +Buy Me A Coffee diff --git a/themes/archie/archetypes/default.md b/themes/archie/archetypes/default.md new file mode 100644 index 0000000..ac36e06 --- /dev/null +++ b/themes/archie/archetypes/default.md @@ -0,0 +1,2 @@ ++++ ++++ diff --git a/themes/archie/exampleSite/archetypes/default.md b/themes/archie/exampleSite/archetypes/default.md new file mode 100644 index 0000000..26f317f --- /dev/null +++ b/themes/archie/exampleSite/archetypes/default.md @@ -0,0 +1,5 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- diff --git a/themes/archie/exampleSite/config.toml b/themes/archie/exampleSite/config.toml new file mode 100644 index 0000000..ec4ec0b --- /dev/null +++ b/themes/archie/exampleSite/config.toml @@ -0,0 +1,47 @@ +baseURL = "https://example.com" +languageCode = "en-us" +title = "Archie" +theme="archie" +copyright = "© Athul" +pygmentsstyle = "monokai" +pygmentscodefences = true +pygmentscodefencesguesssyntax = true +[params] + mode="auto" + useCDN=false + subtitle = "Minimal and Clean [blog theme for Hugo](https://github.com/athul/archie)" + +[[params.social]] +name = "GitHub" +icon = "github" +url = "https://github.com/athul/archie" + +[[params.social]] +name = "Twitter" +icon = "twitter" +url = "https://twitter.com/athulcajay/" + +[[params.social]] +name = "GitLab" +icon = "gitlab" +url = "https://gitlab.com/athul/" + +[[menu.main]] +name = "Home" +url = "/" +weight = 1 + +[[menu.main]] +name = "All posts" +url = "/posts" +weight = 2 + +[[menu.main]] +name = "About" +url = "/about" +weight = 3 + +[[menu.main]] +name = "Tags" +url = "/tags" +weight = 4 diff --git a/themes/archie/exampleSite/content/_index.md b/themes/archie/exampleSite/content/_index.md new file mode 100644 index 0000000..6abc75e --- /dev/null +++ b/themes/archie/exampleSite/content/_index.md @@ -0,0 +1,4 @@ ++++ +author = "Hugo Authors" ++++ + diff --git a/themes/archie/exampleSite/content/about.md b/themes/archie/exampleSite/content/about.md new file mode 100644 index 0000000..a412806 --- /dev/null +++ b/themes/archie/exampleSite/content/about.md @@ -0,0 +1,28 @@ ++++ +title = "About" +description = "Hugo, the world’s fastest framework for building websites" +date = "2019-02-28" +aliases = ["about-us","about-hugo","contact"] +author = "Hugo Authors" ++++ + +Written in Go, Hugo is an open source static site generator available under the [Apache Licence 2.0.](https://github.com/gohugoio/hugo/blob/master/LICENSE) Hugo supports TOML, YAML and JSON data file types, Markdown and HTML content files and uses shortcodes to add rich content. Other notable features are taxonomies, multilingual mode, image processing, custom output formats, HTML/CSS/JS minification and support for Sass SCSS workflows. + +Hugo makes use of a variety of open source projects including: + +* https://github.com/yuin/goldmark +* https://github.com/alecthomas/chroma +* https://github.com/muesli/smartcrop +* https://github.com/spf13/cobra +* https://github.com/spf13/viper + +Hugo is ideal for blogs, corporate websites, creative portfolios, online magazines, single page applications or even a website with thousands of pages. + +Hugo is for people who want to hand code their own website without worrying about setting up complicated runtimes, dependencies and databases. + +Websites built with Hugo are extremelly fast, secure and can be deployed anywhere including, AWS, GitHub Pages, Heroku, Netlify and any other hosting provider. + +Learn more and contribute on [GitHub](https://github.com/gohugoio). + + + diff --git a/themes/archie/exampleSite/content/archives.md b/themes/archie/exampleSite/content/archives.md new file mode 100644 index 0000000..98a1ee9 --- /dev/null +++ b/themes/archie/exampleSite/content/archives.md @@ -0,0 +1,5 @@ +--- +date: 2019-05-28 +type: section +layout: "archives" +--- \ No newline at end of file diff --git a/themes/archie/exampleSite/content/homepage/about.md b/themes/archie/exampleSite/content/homepage/about.md new file mode 100644 index 0000000..c2ba680 --- /dev/null +++ b/themes/archie/exampleSite/content/homepage/about.md @@ -0,0 +1,7 @@ +--- +title: 'Our Difference' +button: 'About us' +weight: 2 +--- + +Lorem ipsum dolor sit amet, et essent mediocritatem quo, choro volumus oporteat an mei. ipsum dolor sit amet, et essent mediocritatem quo, \ No newline at end of file diff --git a/themes/archie/exampleSite/content/homepage/index.md b/themes/archie/exampleSite/content/homepage/index.md new file mode 100644 index 0000000..01ffa31 --- /dev/null +++ b/themes/archie/exampleSite/content/homepage/index.md @@ -0,0 +1,3 @@ +--- +headless : true +--- diff --git a/themes/archie/exampleSite/content/homepage/work.md b/themes/archie/exampleSite/content/homepage/work.md new file mode 100644 index 0000000..f2fee73 --- /dev/null +++ b/themes/archie/exampleSite/content/homepage/work.md @@ -0,0 +1,7 @@ +--- +title: 'We Help Business Grow' +button: 'Our Work' +weight: 1 +--- + +Lorem ipsum dolor sit amet, et essent mediocritatem quo, choro volumus oporteat an mei. Numquam dolores mel eu, mea docendi omittantur et, mea ea duis erat. Elit melius cu ius. Per ex novum tantas putant, ei his nullam aliquam apeirian. Aeterno quaestio constituto sea an, no eum intellegat assueverit. \ No newline at end of file diff --git a/themes/archie/exampleSite/content/posts/post-1.md b/themes/archie/exampleSite/content/posts/post-1.md new file mode 100644 index 0000000..293bdc3 --- /dev/null +++ b/themes/archie/exampleSite/content/posts/post-1.md @@ -0,0 +1,62 @@ +--- +title: "Primer: When You Have Too Much to Do" +date: 2020-04-01T02:01:58+05:30 +description: "You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more." +tags: [Primer, todo] +--- + +You have a to-do list that scrolls on for days. You are managing multiple projects, getting lots of email and messages on different messaging systems, managing finances and personal health habits and so much more. + +It all keeps piling up, and it can feel overwhelming. + +How do you keep up with it all? How do you find focus and peace and get stuff accomplished when you have too much on your plate? + +In this primer, I’ll look at some key strategies and tactics for taking on an overloaded life with an open heart, lots of energy, and a smile on your face. + +## The First Step: Triage + +Whether you’re just starting your day, or you’re in the middle of the chaos and just need to find some sanity … the first step is to get into triage mode. + +Triage, as you probably know, is sorting through the chaos to prioritize: what needs to be done now, what needs to be done today, what needs to be done this week, and what can wait? You’re looking at urgency, but also what’s meaningful and important. + +Here’s what you might do: + +* Pick out the things that need to be done today. Start a Short List for things you’re going to do today. That might be important tasks for big projects, urgent tasks that could result in damage if you don’t act, smaller admin tasks that you really should take care of today, and responding to important messages. I would recommend being ruthless and cutting out as much as you can, having just 5 things on your plate if that’s at all possible. Not everything needs to be done today, and not every email needs to be responded to. +* Push some things to tomorrow and the rest of the week. If you have deadlines that can be pushed back (or renegotiated), do that. Spread the work out over the week, even into next week. What needs to be done tomorrow? What can wait a day or two longer? +* Eliminate what you can. That might mean just not replying to some messages that aren’t that important and don’t really require a reply. It might mean telling some people that you can’t take on this project after all, or that you need to get out of the commitment that you said you’d do. Yes, this is uncomfortable. For now, just put them on a list called, “To Not Do,” and plan to figure out how to get out of them later. + +OK, you have some breathing room and a manageable list now! Let’s shrink that down even further and just pick one thing. + +## Next: Focus on One Thing + +With a lot on your plate, it’s hard to pick one thing to focus on. But that’s exactly what I’m going to ask you to do. + +Pick one thing, and give it your focus. Yes, there are a lot of other things you can focus on. Yes, they’re stressing you out and making it hard to focus. But think about it this way: if you allow it all to be in your head all the time, that will always be your mode of being. You’ll always be thinking about everything, stressing out about it all, with a frazzled mind … unless you start shifting. + +The shift: + +* Pick something to focus on. Look at the triaged list from the first section … if you have 5-6 things on this Short List, you can assess whether there’s any super urgent, time-sensitive things you need to take care of. If there are, pick one of them. If not, pick the most important one — probably the one you have been putting off doing. +* Clear everything else away. Just for a little bit. Close all browser tabs, turn off notifications, close open applications, put your phone away. +* Put that one task before you, and allow yourself to be with it completely. Pour yourself into it. Think of it as a practice, of letting go (of everything else), of focus, of radical simplicity. + +When you’re done (or after 15-20 minutes have gone by at least), you can switch to something else. But don’t allow yourself to switch until then. + +By closing off all exits, by choosing one thing, by giving yourself completely to that thing … you’re now in a different mode that isn’t so stressful or spread thin. You’ve started a shift that will lead to focus and sanity. + +## Third: Schedule Time to Simplify + +Remember the To Not Do list above? Schedule some time this week to start reducing your projects, saying no to people, getting out of commitments, crossing stuff off your task list … so that you can have some sanity back. + +There are lots of little things that you’ve said “yes” to that you probably shouldn’t have. That’s why you’re overloaded. Protect your more important work, and your time off, and your peace of mind, by saying “no” to things that aren’t as important. + +Schedule the time to simplify — you don’t have to do it today, but sometime soon — and you can then not have to worry about the things on your To Not Do list until then. + +## Fourth: Practice Mindful Focus + +Go through the rest of the day with an attitude of “mindful focus.” That means that you are doing one thing at a time, being as present as you can, switching as little as you can. + +Think of it as a settling of the mind. A new mode of being. A mindfulness practice (which means you won’t be perfect at it). + +As you practice mindful focus, you’ll learn to practice doing things with an open heart, with curiosity and gratitude, and even joy. Try these one at a time as you get to do each task on your Short List. + +You’ll find that you’re not so overloaded, but that each task is just perfect for that moment. And that’s a completely new relationship with the work that you do, and a new relationship with life. diff --git a/themes/archie/exampleSite/content/posts/post-2.md b/themes/archie/exampleSite/content/posts/post-2.md new file mode 100644 index 0000000..54f4fde --- /dev/null +++ b/themes/archie/exampleSite/content/posts/post-2.md @@ -0,0 +1,40 @@ +--- +title: "Fearlessness: How to Stop Running from Space" +date: 2018-03-18T12:13:30+05:30 +tags: [Space] +--- + +We spend our days filling in every available space, cramming in more tasks, responding to messages, checking social media and online sites, watching videos. + +We are afraid of empty space in our lives. + +The result is often a continual busyness, constant distraction and avoidance, lack of focus, lack of satisfaction with our lives. + +We run from silence. We run from the spaces between tasks and appointments. We run from solitude and stillness. We try to fill every second with activity, with something useful, as if silence and space are not valuable. + +But what are we afraid of? + +And who would we be if we didn’t have that fear? + +We’re afraid of space and stillness and silence because it highlights the uncertainty, instability, groundlessness, insecurity, shakiness that lie underneath every second of our lives. We’re afraid of having to face this instability and uncertainty, of having to feel the fear of it. + +Without the fear of all of the uncertainty that is highlighted by space … we become free. + +I know in my life, when I allow myself to have stillness, silence, solitude, simplicity and space … it leaves room to face whatever is coming up for me. It gives me room to fully feel any feelings that I’ve been avoiding. It allows me to be more honest with myself, instead of using distractions and busyness to cover up what I don’t want to see. + +And in the end, I develop trust that the space is not something to be feared, but rather something to be treasured. A gift, filled with learning and not knowing and shakiness and beauty. + +You might try allowing more space to be in your day, without filling it: + +* Take some time between tasks for stillness. +* Sit out in nature, in silence, without technology. +* When you notice yourself reaching for your phone, pause. See if you can just be still, just savor some space. +* When you feel uncertainty or instability in your life (hint: it’s always there), let yourself feel it. Be present with it, without needing to run or avoid. +* When you feel fear, be open-hearted with it and allow yourself fully feel it, being friendly with it. Your relationship with fear will change if you become friendly with it. +* Do less, and trust that things won’t fall apart. Or if they do fall apart, you can be present with that instability. +* When you’re in line, driving, eating, walking, exercising … see if you can do those things in silence, without technology, without needing to do something “useful.” Find the value in these spaces. +* Notice who you are without the fear of space. + +Savor these spaces, their deliciousness. Savor the groundlessness, as something filled with freedom if we learn not to fear it. Be present with the fear and uncertainty, as good friends not as enemies. + +Let your heart be open raw tender and vulnerable, and your mind embracing the spaciousness of the vast blue sky of open awareness. diff --git a/themes/archie/exampleSite/content/posts/post-3.md b/themes/archie/exampleSite/content/posts/post-3.md new file mode 100644 index 0000000..2eb633f --- /dev/null +++ b/themes/archie/exampleSite/content/posts/post-3.md @@ -0,0 +1,38 @@ +--- +title: "How I Learned to Stop Procrastinating, & Love Letting Go" +date: 2018-03-18T12:13:32+05:30 +description: "The art of letting go." +tags: [Procrastinating] +--- + +The end of procrastination is the art of letting go. + +I’ve been a lifelong procrastinator, at least until recent years. I would put things off until deadline, because I knew I could come through. I came through on tests after cramming last minute, I turned articles in at the deadline after waiting until the last hour, I got things done. + +Until I didn’t. It turns out procrastinating caused me to miss deadlines, over and over. It stressed me out. My work was less-than-desirable when I did it last minute. Slowly, I started to realize that procrastination wasn’t doing me any favors. In fact, it was causing me a lot of grief. + +But I couldn’t quit. I tried a lot of things. I tried time boxing and goal setting and accountability and the Pomodoro Technique and Getting Things Done. All are great methods, but they only last so long. Nothing really worked over the long term. + +That’s because I wasn’t getting to the root problem. + +I hadn’t figured out the skill that would save me from the procrastination. + +Until I learned about letting go. + +Letting go first came to me when I was quitting smoking. I had to let go of the “need” to smoke, the use of my crutch of cigarettes to deal with stress and problems. + +Then I learned I needed to let go of other false needs that were causing me problems: sugar, junk food, meat, shopping, beer, possessions. I’m not saying I can never do these things again once I let go of these needs, but I let go of the idea that they’re really necessary. I let go of an unhealthy attachment to them. + +Then I learned that distractions and the false need to check my email and news and other things online … were causing me problems. They were causing my procrastination. + +So I learned to let go of those too. + +Here’s the process I used to let go of the distractions and false needs that cause procrastination: + +I paid attention to the pain they cause me, later, instead of only the temporary comfort/pleasure they gave me right away. +I thought about the person I want to be, the life I want to live. I set my intentions to do the good work I think I should do. +I watched my urges to check things, to go to the comfort of distractions. I saw that I wanted to escape discomfort of something hard, and go to the comfort of something familiar and easy. +I realized I didn’t need that comfort. I could be in discomfort and nothing bad would happen. In fact, the best things happen when I’m in discomfort. +And then I smile, and breathe, and let go. + +And one step at a time, become the person I want to be. diff --git a/themes/archie/exampleSite/content/posts/post-4.md b/themes/archie/exampleSite/content/posts/post-4.md new file mode 100644 index 0000000..e6609a7 --- /dev/null +++ b/themes/archie/exampleSite/content/posts/post-4.md @@ -0,0 +1,30 @@ +--- +title: "Getting Started with Traveling Ultralight" +date: 2020-03-18T12:13:35+05:30 +description: "Start by getting a small backpack (less than 20 liters) and then just travel with what fits in that." +--- + +I’m on a trip at the moment, and a friend who generously let me sleep on his couch looked at my small travel backpack and commented on how little I travel with: “That’s impressive,” he said. + +I was a little surprised, because though I’ve gotten that comment before, it’s become normal for me to travel with just a small bag (10 lbs. or less, usually), and I have friends who travel with even less. But then I remembered that I’m far from normal in this way. + +I gave him a tip for getting started, and I recommend it for all of you, who want to travel light — or ultralight, as I call it, because for many people traveling light is taking a carry-on roller luggage. For me, having those roller bags is lugging too much, because you can run up stairs with it with ease, or carry it all over a city without worrying about stowing away your luggage somewhere first. It’s so much easier to travel ultralight. + +Here’s the tip I gave him to get started: start by getting a small backpack (less than 20 liters) and then just travel with what fits in that. + +That’s how to start. But you’ll probably want some guidance on what to put into the bag, and how to travel with so little. Here’s some guidance to get started: + +* I travel with a lightweight laptop (Macbook Air), a few clothes, my phone, earbuds and some charging cords, toiletries, and almost nothing else. A lightweight windbreaker for wind and light rain (Patagonia Houdini). An eye mask and ear plugs. A collapsible water bottle. My passport. That’s about it. No extra shoes. No books. No suit. No travel pillow. No extra camera other than my phone. I’m not sure what else everyone else brings, but none of that. +* I bring clothes that I can wash in the sink or shower and that will dry overnight. Lightweight stuff that I can layer. Often they’re workout-style clothes or things from companies like Outlier or Patagonia that travel well. I don’t bring enough underwear or socks for every day of the trip, because I wash them every couple of days. I only bring one or two extra T-shirts, generally wearing the same two shirts the whole trip, even if it’s a month long. No one has ever once cared what I wear when I’m traveling. +* I bring minimal toiletries: a small shaver for my head, razor, toothbrush, floss small tubes of toothpaste and shaving cream, deodorant, nail clippers, ibuprofen. +* For cold places, I have thermal underwear and a couple long-sleeve layers (generally all Patagonia capilene stuff), and a beanie. I don’t usually go to places where it’s snowing (I don’t know why, maybe snow isn’t my thing), so I don’t have clothes to deal with that weather. +* For warm places, I will bring flip flops and swim trunks, and leave most of the colder layers behind. + +That’s enough for a monthlong trip, which I’ve done multiple times with this kind of setup. For a shorter trip of a few days, I might bring even less. + +I really love traveling this way, and am more than willing to sacrifice bringing extra things for the luxury of traveling lightweight. + +By the way, you don’t need much more than this kind of setup even in everyday life. + +For more info on this, check out my Ultralight ebook, and my friend Tynan has a great book called Forever Nomad. + diff --git a/themes/archie/exampleSite/content/posts/post-5.md b/themes/archie/exampleSite/content/posts/post-5.md new file mode 100644 index 0000000..8623c19 --- /dev/null +++ b/themes/archie/exampleSite/content/posts/post-5.md @@ -0,0 +1,75 @@ +--- +title: "Typography" +date: 2018-03-18T12:13:38+05:30 +--- + +Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. + +# Heading 1 + +Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. + +## Heading 2 + +Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. + +### Heading 3 + +Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. + +#### Heading 4 + +Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. + +##### Heading 5 + +Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. + +###### Heading 6 + +Lid est laborum et dolorum fuga. Et harum quidem rerum facilis est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit quo minus id quod amets untra dolor amet sad. Sed ut perspser iciatis unde omnis iste natus error sit voluptatem accusantium doloremque laste. Dolores sadips ipsums sits. + +## Typography + +Lid est laborum et dolorum fuga, This is [an example](http://example.com/ "Title") inline link. Et harum quidem rerum facilis, **This is bold** and *emphasis* cumque nihilse impedit quo minus id quod amets untra dolor amet sad. While this is `code block()` and following is a `pre` tag + + print 'this is pre tag' + +Following is the syntax highlighted code block + +```go +func getCookie(name string, r interface{}) (*http.Cookie, error) { + rd := r.(*http.Request) + cookie, err := rd.Cookie(name) + if err != nil { + return nil, err + } + return cookie, nil +} + +func setCookie(cookie *http.Cookie, w interface{}) error { + // Get write interface registered using `Acquire` method in handlers. + wr := w.(http.ResponseWriter) + http.SetCookie(wr, cookie) + return nil +} +``` + +This is blockquote, Will make it *better now* + +> 'I want to do with you what spring does with the cherry trees.' cited ~Pablo Neruda* + + +> Et harum quidem *rerum facilis* est et expeditasi distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihilse impedit + +Unordered list + +* Red +* Green +* Blue + +Ordered list + +1. Red +2. Green +3. Blue diff --git a/themes/archie/exampleSite/content/posts/post-6.md b/themes/archie/exampleSite/content/posts/post-6.md new file mode 100644 index 0000000..5566a71 --- /dev/null +++ b/themes/archie/exampleSite/content/posts/post-6.md @@ -0,0 +1,36 @@ +--- +title: "Hugo shortcodes" +date: 2018-03-18T12:13:36+05:30 +description: Here is a demo of all shortcodes available in Hugo. +--- + +## Images + + + + + + +## Github Gist + +{{< gist spf13 7896402 >}} + +## Youtube video + +{{< youtube w7Ft2ymGmfc >}} + +## Tweet + +{{< tweet 877500564405444608 >}} + +## Vimeo + +{{< vimeo id="146022717" >}} + +## Instagram + +{{< instagram BWNjjyYFxVx >}} + +## Callouts + +{{< callout emoji="⚡️" text="I guess this works" >}} diff --git a/themes/archie/exampleSite/content/posts/post-7.md b/themes/archie/exampleSite/content/posts/post-7.md new file mode 100644 index 0000000..4884040 --- /dev/null +++ b/themes/archie/exampleSite/content/posts/post-7.md @@ -0,0 +1,15 @@ +--- +title: "How to test dark mode?" +summary: "Here is how you can setup dark mode for Ink and test on various OS like iOS, Android, macOS and Windows 10." +date: 2018-03-18T12:13:38+05:30 +tldr: "Wubba lubba dub dub" +--- + +You can set dark mode as default by setting `params.mode` to `dark` in `config.toml` or set it to `auto` which will detect based on your OS and switch to dark mode. For more details [refer documentation](https://github.com/knadh/hugo-ink#configuration) + +Here is how you can switch based on your OS + +* [iOS](https://www.howtogeek.com/440078/how-to-enable-dark-mode-on-your-iphone-and-ipad/) +* [Android](https://9to5google.com/2018/12/17/android-dark-mode-theme-pie/) +* [macOS](https://support.apple.com/en-in/HT208976) +* [Windows 10](https://www.cnet.com/how-to/turn-on-the-dark-mode-in-windows-10/) diff --git a/themes/archie/exampleSite/content/posts/tg-gh.md b/themes/archie/exampleSite/content/posts/tg-gh.md new file mode 100644 index 0000000..4400148 --- /dev/null +++ b/themes/archie/exampleSite/content/posts/tg-gh.md @@ -0,0 +1,382 @@ +--- +title: Telegram Bot for GitHub Actions +date: "2020-04-01" +description: Make a Telegram bot with Node.js and use it with GitHub Actions for sending notifications to you about the repo. +tldr: Making GitHub Actions with Js Code +--- +## Telegram +[Telegram](https://telegram.org/) is a cloud-based mobile and desktop messaging app with a focus on security and speed. It is free to use and extensively hackable. It also has a good bot support system. The API is also easy to implement and has many wrappers for building bots with the API. + +## GitHub Actions +[GitHub Actions](https://github.com/features/actions) is a CI/CD runtime for your GitHub repository. You can run almost anything from scripts to docker containers. You can build, test and deploy your code with GitHub Actions. All these actions are called workflows and workflows differ in the job they're doing. These maybe test workflows, build ones or deployment ones. You can find all the actions on GitHub in the [marketplace](https://github.com/marketplace?type=actions) + +## Building the Bot +### Prerequisites +- Basic JavaScript Knowledge +- Basic GitHub Knowledge +- Telegram Account + +> There are templates for building actions. Here we're gonna start from scratch + +### Environment Setup +- **Node**, You can download node from their [website](https://nodejs.org/en/download/) +- NPM comes with node, so you don't have to worry about it. +- Initialize the Project +```shell +$ git init ## initialize a new git repository for version management +--- +$ npm init +``` +- **dotenv**, Dotenv can be downloaded via +```shell +$ npm i dotenv +--- +$ yarn add dotenv +``` +- **node-telegram-bot-api**, node-telegram-bot-api is a simple wrapper for building telegram bots. You can download it via +```shell +$ npm i node-telegram-bot-api +--- +$ yarn add node-telegram-bot-api +``` +- **@zeit/ncc**, NCC is a Simple CLI for compiling a Node.js module into a single file, together with all its dependencies, GCC-style. It's a dev dependency and can be downloaded +```shell +yarn add --dev @zeit/ncc +--- +npm i -D @zeit/ncc +``` + + +#### Folder Structure +The `dist` folder will be automatically created. `action.yml` will be made + +``` +. +├── dist +│ └── index.js +├── index.js +├── action.yml +├── README.md +└── package.json + +``` +- `index.js` is the file we're defining the bot +- `action.yml` is the file we'll define the action and it's behaviours + +## Making the Bot +We need to get an API bot token from telegram. For that Go to Telegram and Search for `Botfather`. It's a bot. +![](bfather.png) +Create a new bot with the `/newbot` command and get the API key. We'll need that, also talk to `jsondump` bot and get your chat id. The output may be like this, so +```json +{ + "update_id": 143943779, + "message": { + "message_id": 181575, + "from": { + "id": 123456 // this is what we need + "is_bot": false, + "first_name": "Tg Name", + "username": "TG Username", + "language_code": "en" + }, + "chat": { + "id": 123456, + "first_name": "Tg Name", + "username": "TG Username", + "type": "private" + }, + "date": 1584119424, + "text": "message" + } +} +``` +This will be needed for further use and We need to add it to the repo secrets which can be found in the repo settings. Be careful to add it as `token` and `chat` like as shown below +![](scr.png) + +### Writing the Action and Building the Bot +Fire up the terminal/cmd and make a new folder. Install the dependencies. Run the following command +```shell +$ touch index.js action.yml +``` +Open your favourite text editor within the folder or with the file. We'll define the bot in `index.js` + +```javaScript +require("dotenv").config +const Bot = require('node-telegram-bot-api'); +const { + INPUT_STATUS: ipstatus, + INPUT_TOKEN: tgtoken,//Telegram api token + INPUT_CHAT: chatid,// Telegram Chat ID + INPUT_IU_TITLE: ititle,// Issue title + INPUT_IU_NUM: inum,// Issue Number + INPUT_IU_ACTOR: iactor,// Issue made by + INPUT_IU_BODY: ibody,// Issue Body + INPUT_PR_NUM: pnum,// PR Number + INPUT_PR_STATE: prstate,// PR Opened, reponed or closed + INPUT_PR_TITLE: ptitle,// PR Title + INPUT_PR_BODY: pbody,// Body of the PR + GITHUB_EVENT_NAME: ghevent,// Name of the trigger event + GITHUB_REPOSITORY: repo,// Repository the trigger was made from + GITHUB_ACTOR: ghactor,// User who triggered the action + GITHUB_SHA: sha,// Commit ID + GITHUB_WORKFLOW: ghwrkflw// Workflow Name +} = process.env; + +const bot = new Bot(tgtoken) +``` +First, we're defining the dotenv for config and initializing Telegram Bot. Here we're defining the alias variables for the *environment variables*. You might notice an `INPUT_` for almost every environment variable, this is because GitHub Actions pass the env variable with an INPUT prefix. Other env variables are action's default environment variables. Then we initialized the bot with the API token. + +GitHub actions could be triggered with Issues, Pull Request or Pushes. You can find the trigger events [here](https://help.github.com/en/actions/reference/events-that-trigger-workflows). Here we're gonna get a message from the bot when an *Issue* or *Pull Request* or a *Push* event has happened. + +```js +const evresp = (gevent) => { + switch (gevent) { + + case "issues": + return ` +❗️❗️❗️❗️❗️❗️ + +Issue ${prstate} + +Issue Title and Number : ${ititle} | #${inum} + +Commented or Created By : \`${iactor}\` + +Issue Body : *${ibody}* + +[Link to Issue](https://github.com/${repo}/issues/${inum}) +[Link to Repo ](https://github.com/${repo}/) +[Build log here](https://github.com/${repo}/commit/${sha}/checks)` + case "pull_request": + return ` +🔃🔀🔃🔀🔃🔀 +PR ${prstate} + +PR Number: ${pnum} + +PR Title: ${ptitle} + +PR Body: *${pbody}* + +PR By: ${ghactor} + +[Link to Issue](https://github.com/${repo}/pull/${pnum}) +[Link to Repo ](https://github.com/${repo}/) +[Build log here](https://github.com/${repo}/commit/${sha}/checks)` + default: + return ` +⬆️⇅⬆️⇅ + +ID: ${ghwrkflw} + +Action was a *${ipstatus}!* + +\`Repository: ${repo}\` + +On: *${ghevent}* + +By: *${ghactor}* + +Tag: ${process.env.GITHUB_REF} + +[Link to Repo ](https://github.com/${repo}/) + ` + } +} +``` +In these lines of code, we're just initializing a switch statement for the responses. We're also declaring an anonymous function to use the switch responses via a function later. We're using all the defined variables in the switch. You can check the [trigger Events](https://help.github.com/en/actions/reference/events-that-trigger-workflows) to get how the event is triggered and what keyword should be used. + +Now for the last part of the Js file, we just take the response from the switch and assign it to a constant. Then we use the `sendMessage` function of the `node-telegram-bot-api` to send the message to the bot with the chatid and the output as the arguments. +```js +const output = evresp(ghevent) +``` +bot.sendMessage(chatid,output,{parse_mode : "Markdown"}) +## Compiling and Minifying the Js code +Since we have installed `@zeit/ncc` and this is used for the making the whole program with all the APIs to a single file and we need to use NCC for that. We just need to run +```shell +yarn run ncc build index.js -C -m -o dist +``` +or you might wanna add the following to you `package.json` file, and run `npm run test` to compile and minify the code. +```json +"scripts": { + "test": "ncc build index.js -C -m -o dist" + }, +``` +This will create a `dist` folder with and `index.js` file which contains the compiled code. + +## Making it a valid action +For making this Js file a valid action, we need to add an `action.yml` file. The action.yml for this action is like this +```yml +name: 'Action Name' +description: 'Action Descreption' +author: '' +inputs: + chat: + description: 'Chat to send: chat id or @channel_name' + required: true + token: + description: 'Telegram Bot token' + required: true + status: + description: 'Job status' + required: true + iu_title: + description: 'Issue Title' + default: ${{ github.event.issue.title }} + iu_num: + description: 'Issue Number' + default: ${{ github.event.issue.number }} + iu_actor: + description: 'Issue Triggerer' + default: ${{ github.event.issue.user.login }} + iu_com: + description: 'Issue Comment' + default: ${{github.event.comment.body}} + pr_state: + description: 'State of the PR' + default: ${{ github.event.action }} + pr_num: + description: 'PR Number' + default: ${{ github.event.number }} + pr_title: + description: 'Title of the PR' + default: ${{ github.event.pull_request.title }} + pr_body: + description: 'Body/Contents of the PR' + default: ${{ github.event.pull_request.body }} +runs: + using: "node12" + main: "dist/index.js" +branding: + icon: 'repeat' + color: 'green' +``` +Here we're defining the Input variables to be loaded for the action in GitHub's runtime environemt. All these `default` data are taken from the response of the webhooks which are send by GitHub when a trigger event is occured. You can find out more in the [Action Documentation Here](https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context). + +```yml +runs: + using: "node12" + main: "dist/index.js" +``` +Here we are defining that this is a node action and should run in an environment with node, and the file which should be run, here the `index.js` file in the `dist` folder. That should do it. Create a new commit and push it to a repo. **Create a new tag** and this action will appear in the [marketplace](https://github.com/marketplace?type=actions). + +### Defining a workflow to test your action +GitHub Action workflows are defined using the `.yml` syntax. Here is an example of a sample workflow for this action + +```yml +name: + +on: + push: + pull_request: + types: [opened, closed] + issues: + types: [opened, closed, reopened] +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: + uses: /@master + if: always() + with: + chat: ${{ secrets.chat }} + token: ${{ secrets.token }} + status: ${{ job.status }} +``` + + +The Complete code for the bot is +```js +//Initializing dotenv and the bot +require("dotenv").config +const Bot = require('node-telegram-bot-api'); +// aliasing the environment variables +const { + INPUT_STATUS: ipstatus, + INPUT_TOKEN: tgtoken, //Telegram api token + INPUT_CHAT: chatid,// Telegram Chat ID + INPUT_IU_TITLE: ititle,// Issue title + INPUT_IU_NUM: inum,// Issue Number + INPUT_IU_ACTOR: iactor, // Issue made by + INPUT_IU_BODY: ibody, // Issue Body + INPUT_PR_NUM: pnum, // PR Number + INPUT_PR_STATE: prstate, // PR Opened, reponed or closed + INPUT_PR_TITLE: ptitle, // PR Title + INPUT_PR_BODY: pbody, // Body of the PR + GITHUB_EVENT_NAME: ghevent, // Name of the trigger event + GITHUB_REPOSITORY: repo, // Repository the trigger was made from + GITHUB_ACTOR: ghactor, // User who triggered the action + GITHUB_SHA: sha, // Commit ID + GITHUB_WORKFLOW: ghwrkflw // Workflow Name +} = process.env; + +const bot = new Bot(tgtoken) +// Function to return the response for the specific trigger +const evresp = (gevent) => { + switch (gevent) { +//Switch statement for issues + case "issues": + return ` +❗️❗️❗️❗️❗️❗️ + +Issue ${prstate} + +Issue Title and Number : ${ititle} | #${inum} + +Commented or Created By : \`${iactor}\` + +Issue Body : *${ibody}* + +[Link to Issue](https://github.com/${repo}/issues/${inum}) +[Link to Repo ](https://github.com/${repo}/) +[Build log here](https://github.com/${repo}/commit/${sha}/checks)` +// Switch statement for Pull Requests + case "pull_request": + return ` +🔃🔀🔃🔀🔃🔀 +PR ${prstate} + +PR Number: ${pnum} + +PR Title: ${ptitle} + +PR Body: *${pbody}* + +PR By: ${ghactor} + +[Link to Issue](https://github.com/${repo}/pull/${pnum}) +[Link to Repo ](https://github.com/${repo}/) +[Build log here](https://github.com/${repo}/commit/${sha}/checks)` + default: +// switch statement for Pushes + return ` +⬆️⇅⬆️⇅ + +ID: ${ghwrkflw} + +Action was a *${ipstatus}!* + +\`Repository: ${repo}\` + +On: *${ghevent}* + +By: *${ghactor}* + +Tag: ${process.env.GITHUB_REF} + +[Link to Repo ](https://github.com/${repo}/) + ` + } +} +// assigning the output to a variable +const output = evresp(ghevent) +// sending the message +bot.sendMessage(chatid,output,{parse_mode : "Markdown"}) +``` + + +------ + +You can try out many different items using actions and this is just a sample action to get you started. Maybe sending Cat GIFs if the build succeded on the pull request or sending a welcome message to a first time contributor. You imagination is the limit😄 and **Never Stop being ⚡️** \ No newline at end of file diff --git a/themes/archie/images/archie-dark.png b/themes/archie/images/archie-dark.png new file mode 100644 index 0000000..2bff9ed Binary files /dev/null and b/themes/archie/images/archie-dark.png differ diff --git a/themes/archie/images/theme.png b/themes/archie/images/theme.png new file mode 100644 index 0000000..c195540 Binary files /dev/null and b/themes/archie/images/theme.png differ diff --git a/themes/archie/layouts/404.html b/themes/archie/layouts/404.html new file mode 100644 index 0000000..1a45af9 --- /dev/null +++ b/themes/archie/layouts/404.html @@ -0,0 +1,9 @@ +{{ partial "header.html" . }} + +
+
+

404 NOT FOUND

+
+
+ +{{ partial "footer.html" . }} \ No newline at end of file diff --git a/themes/archie/layouts/_default/baseof.html b/themes/archie/layouts/_default/baseof.html new file mode 100644 index 0000000..b941097 --- /dev/null +++ b/themes/archie/layouts/_default/baseof.html @@ -0,0 +1,11 @@ + + + {{- partial "header.html" . -}} + +
+ {{- partial "head.html" . -}} + {{- block "main" . }}{{- end }} + {{- partial "footer.html" . -}} +
+ + diff --git a/themes/archie/layouts/_default/list.html b/themes/archie/layouts/_default/list.html new file mode 100644 index 0000000..41a4c6f --- /dev/null +++ b/themes/archie/layouts/_default/list.html @@ -0,0 +1,17 @@ +{{ define "main" }} +{{ if isset .Data "Term" }} +

Entries tagged - "{{ .Data.Term }}"

+{{ else }} +

All articles

+{{ end }} + +
    + {{- range .Data.Pages -}} + {{- if (not (in (.Site.Params.excludedTypes | default (slice "page")) .Type)) -}} +
  • + {{.Title}} {{ dateFormat "Jan 2, 2006" .Date }}{{ if .Draft }} DRAFT {{ end }} +
  • + {{- end -}} + {{- end -}} +
+{{ end }} diff --git a/themes/archie/layouts/_default/single.html b/themes/archie/layouts/_default/single.html new file mode 100644 index 0000000..8433db0 --- /dev/null +++ b/themes/archie/layouts/_default/single.html @@ -0,0 +1,42 @@ +{{ define "main" }} +
+
+
+

{{ .Title }}

+
Posted on {{ dateFormat "Jan 2, 2006" .Date }}{{ if .Draft }} DRAFT {{ end }}
+
+ {{ if isset .Params "tldr" }} +
+ tl;dr: + {{ .Params.tldr }} +
{{ end }} + +
+ {{ .Content }} +
+ + + {{- $.Scratch.Set "isDisqus" true -}} + + {{ if not .Site.DisqusShortname }} + {{- $.Scratch.Set "isDisqus" false -}} + {{ end }} + + {{- if eq ($.Scratch.Get "isDisqus") true -}} + {{- partial "disqus.html" . -}} + {{- end -}} +
+
+{{ end }} diff --git a/themes/archie/layouts/_default/term.html b/themes/archie/layouts/_default/term.html new file mode 100644 index 0000000..41a4c6f --- /dev/null +++ b/themes/archie/layouts/_default/term.html @@ -0,0 +1,17 @@ +{{ define "main" }} +{{ if isset .Data "Term" }} +

Entries tagged - "{{ .Data.Term }}"

+{{ else }} +

All articles

+{{ end }} + +
    + {{- range .Data.Pages -}} + {{- if (not (in (.Site.Params.excludedTypes | default (slice "page")) .Type)) -}} +
  • + {{.Title}} {{ dateFormat "Jan 2, 2006" .Date }}{{ if .Draft }} DRAFT {{ end }} +
  • + {{- end -}} + {{- end -}} +
+{{ end }} diff --git a/themes/archie/layouts/_default/terms.html b/themes/archie/layouts/_default/terms.html new file mode 100644 index 0000000..fea9c2f --- /dev/null +++ b/themes/archie/layouts/_default/terms.html @@ -0,0 +1,20 @@ +{{ define "main" }} +

All tags

+ +{{ $biggest := 1 }} +{{ $smallest := 1 }} +{{ $max := 3 }} +{{ $min := 1 }} +{{ $size := $min }} + +{{ $data := .Data }} +
+
    + {{ range $key, $value := .Data.Terms.ByCount }} + {{ $size := (add (mul (div $value.Count $biggest) (sub $max $min)) $min) }} + {{ $size := (cond (eq $biggest $smallest) $min $size) }} +
  • {{ $value.Name }}
  • + {{ end }} +
+
+{{ end }} diff --git a/themes/archie/layouts/index.html b/themes/archie/layouts/index.html new file mode 100644 index 0000000..20b42a9 --- /dev/null +++ b/themes/archie/layouts/index.html @@ -0,0 +1,32 @@ + + + {{ partial "header.html" . }} + +
+ {{ partial "head.html" . }} + +
+ {{ .Content }} +
+ + +

Latest Posts

+ +
+ + {{ $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections }} + {{ $paginator := .Paginate (where $pages "Params.hidden" "ne" true) }} + {{ range $paginator.Pages }} +
+ {{.Title}} + + Read more ⟶ +
+ {{ end }} + {{ template "partials/paginator.html" . }} +
+ {{ partial "footer.html" . }} +
+ + + diff --git a/themes/archie/layouts/partials/disqus.html b/themes/archie/layouts/partials/disqus.html new file mode 100644 index 0000000..11bd488 --- /dev/null +++ b/themes/archie/layouts/partials/disqus.html @@ -0,0 +1,19 @@ +
+ + +comments powered by Disqus \ No newline at end of file diff --git a/themes/archie/layouts/partials/foot_custom.html b/themes/archie/layouts/partials/foot_custom.html new file mode 100644 index 0000000..e69de29 diff --git a/themes/archie/layouts/partials/footer.html b/themes/archie/layouts/partials/footer.html new file mode 100644 index 0000000..b84cd91 --- /dev/null +++ b/themes/archie/layouts/partials/footer.html @@ -0,0 +1,21 @@ +
+
+ {{- range $index, $key := .Site.Params.Social -}} + + + {{- end -}} +
+ +
+{{ if not .Site.IsServer }} +{{ template "_internal/google_analytics.html" . }} +{{ end }} + +{{- if (isset .Site.Params "social") -}} + +{{- end -}} diff --git a/themes/archie/layouts/partials/head.html b/themes/archie/layouts/partials/head.html new file mode 100644 index 0000000..73825b0 --- /dev/null +++ b/themes/archie/layouts/partials/head.html @@ -0,0 +1,16 @@ +
+ + +
+ +{{ partial "head_custom.html" . }} \ No newline at end of file diff --git a/themes/archie/layouts/partials/head_custom.html b/themes/archie/layouts/partials/head_custom.html new file mode 100644 index 0000000..e69de29 diff --git a/themes/archie/layouts/partials/header.html b/themes/archie/layouts/partials/header.html new file mode 100644 index 0000000..0eabefa --- /dev/null +++ b/themes/archie/layouts/partials/header.html @@ -0,0 +1,104 @@ + + + + {{- $title := ( .Title ) -}} + {{- $siteTitle := ( .Site.Title ) -}} + {{- if .IsHome -}} + {{ $siteTitle }} | Home + {{- else -}} + {{ $title }} - {{ $siteTitle }} + {{- end -}} + + {{- if isset .Site.Params "favicon" -}} + + {{- end -}} + + + + + {{ with .OutputFormats.Get "rss" -}} + {{ printf `` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }} + {{ end -}} + + {{- template "_internal/opengraph.html" . -}} + {{- template "_internal/twitter_cards.html" . -}} + {{ if and (isset .Site.Params "social") (.Site.Params.useCDN | default false) -}} + + {{- else if or (isset .Site.Params "social") (eq .Site.Params.mode "toggle") -}} + + {{ end }} + {{ if .Site.Params.useCDN | default false -}} + + + + {{- else -}} + {{ $fontstyle := resources.Get "css/fonts.css" | fingerprint }} + + {{ end }} + + {{ $style := resources.Get "css/main.css" | fingerprint }} + + + {{- if or (eq .Site.Params.mode "auto") (eq .Site.Params.mode "dark") (eq .Site.Params.mode "toggle") -}} + {{ $darkstyle := resources.Get "css/dark.css" | fingerprint }} + + {{ end }} + + + {{ with .Site.Params.mathjax }} + + + + + {{ end }} + + + {{ with .Site.Params.katex }} + + + + + + + {{ end }} + + + {{- if isset .Site.Params "customcss" }} + {{ range .Site.Params.customCSS }} + {{ $customstyle := resources.Get . | fingerprint }} + + {{ end }} + {{- end -}} + {{- range .Site.Params.customJS }} + {{- if or (hasPrefix . "http://") (hasPrefix . "https://") }} + + {{- else if (hasPrefix . " + {{- end }} + {{- end }} + diff --git a/themes/archie/layouts/partials/pagedescription.html b/themes/archie/layouts/partials/pagedescription.html new file mode 100644 index 0000000..d69bb9a --- /dev/null +++ b/themes/archie/layouts/partials/pagedescription.html @@ -0,0 +1,7 @@ +
+ {{ if isset .Params "description" }} + {{ .Description }} + {{ else }} + {{ .Summary }}… + {{ end }} +
\ No newline at end of file diff --git a/themes/archie/layouts/partials/paginator.html b/themes/archie/layouts/partials/paginator.html new file mode 100644 index 0000000..5acc06d --- /dev/null +++ b/themes/archie/layouts/partials/paginator.html @@ -0,0 +1,15 @@ +{{ $pag := $.Paginator }} +{{ if gt $pag.TotalPages 1 }} +
    + + {{ if $pag.HasPrev }} + + {{ end }} + + + {{ if $pag.HasNext }} + + {{ end }} + +
+{{ end }} diff --git a/themes/archie/layouts/shortcodes/callout.html b/themes/archie/layouts/shortcodes/callout.html new file mode 100644 index 0000000..5557aad --- /dev/null +++ b/themes/archie/layouts/shortcodes/callout.html @@ -0,0 +1,6 @@ + +
+
+ 💡 {{ .Get "text" }} +
+
\ No newline at end of file diff --git a/themes/archie/static/fonts/fira-sans-v10-latin-regular.eot b/themes/archie/static/fonts/fira-sans-v10-latin-regular.eot new file mode 100644 index 0000000..7abf4c2 Binary files /dev/null and b/themes/archie/static/fonts/fira-sans-v10-latin-regular.eot differ diff --git a/themes/archie/static/fonts/fira-sans-v10-latin-regular.svg b/themes/archie/static/fonts/fira-sans-v10-latin-regular.svg new file mode 100644 index 0000000..1e52097 --- /dev/null +++ b/themes/archie/static/fonts/fira-sans-v10-latin-regular.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/themes/archie/static/fonts/fira-sans-v10-latin-regular.ttf b/themes/archie/static/fonts/fira-sans-v10-latin-regular.ttf new file mode 100644 index 0000000..572e442 Binary files /dev/null and b/themes/archie/static/fonts/fira-sans-v10-latin-regular.ttf differ diff --git a/themes/archie/static/fonts/fira-sans-v10-latin-regular.woff b/themes/archie/static/fonts/fira-sans-v10-latin-regular.woff new file mode 100644 index 0000000..d99ba57 Binary files /dev/null and b/themes/archie/static/fonts/fira-sans-v10-latin-regular.woff differ diff --git a/themes/archie/static/fonts/fira-sans-v10-latin-regular.woff2 b/themes/archie/static/fonts/fira-sans-v10-latin-regular.woff2 new file mode 100644 index 0000000..9bb5760 Binary files /dev/null and b/themes/archie/static/fonts/fira-sans-v10-latin-regular.woff2 differ diff --git a/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.eot b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.eot new file mode 100644 index 0000000..62b89b3 Binary files /dev/null and b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.eot differ diff --git a/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.svg b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.svg new file mode 100644 index 0000000..6423805 --- /dev/null +++ b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.svg @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.ttf b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.ttf new file mode 100644 index 0000000..e4d1ddf Binary files /dev/null and b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.ttf differ diff --git a/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.woff b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.woff new file mode 100644 index 0000000..4504b41 Binary files /dev/null and b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.woff differ diff --git a/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.woff2 b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.woff2 new file mode 100644 index 0000000..489745d Binary files /dev/null and b/themes/archie/static/fonts/ibm-plex-mono-v6-latin-500italic.woff2 differ diff --git a/themes/archie/static/fonts/roboto-mono-v12-latin-regular.eot b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.eot new file mode 100644 index 0000000..8c56483 Binary files /dev/null and b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.eot differ diff --git a/themes/archie/static/fonts/roboto-mono-v12-latin-regular.svg b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.svg new file mode 100644 index 0000000..1864328 --- /dev/null +++ b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.svg @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/themes/archie/static/fonts/roboto-mono-v12-latin-regular.ttf b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.ttf new file mode 100644 index 0000000..d5dee83 Binary files /dev/null and b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.ttf differ diff --git a/themes/archie/static/fonts/roboto-mono-v12-latin-regular.woff b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.woff new file mode 100644 index 0000000..f319fbf Binary files /dev/null and b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.woff differ diff --git a/themes/archie/static/fonts/roboto-mono-v12-latin-regular.woff2 b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.woff2 new file mode 100644 index 0000000..ed384d2 Binary files /dev/null and b/themes/archie/static/fonts/roboto-mono-v12-latin-regular.woff2 differ diff --git a/themes/archie/static/js/feather.min.js b/themes/archie/static/js/feather.min.js new file mode 100644 index 0000000..d229492 --- /dev/null +++ b/themes/archie/static/js/feather.min.js @@ -0,0 +1,13 @@ +!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.feather=n():e.feather=n()}("undefined"!=typeof self?self:this,function(){return function(e){var n={};function i(l){if(n[l])return n[l].exports;var t=n[l]={i:l,l:!1,exports:{}};return e[l].call(t.exports,t,t.exports,i),t.l=!0,t.exports}return i.m=e,i.c=n,i.d=function(e,n,l){i.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:l})},i.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},i.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(n,"a",n),n},i.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},i.p="",i(i.s=61)}([function(e,n,i){var l=i(20)("wks"),t=i(11),r=i(1).Symbol,o="function"==typeof r;(e.exports=function(e){return l[e]||(l[e]=o&&r[e]||(o?r:t)("Symbol."+e))}).store=l},function(e,n){var i=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=i)},function(e,n){var i=e.exports={version:"2.5.6"};"number"==typeof __e&&(__e=i)},function(e,n){var i={}.hasOwnProperty;e.exports=function(e,n){return i.call(e,n)}},function(e,n,i){e.exports=!i(27)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,n,i){var l=i(13);e.exports=function(e){if(!l(e))throw TypeError(e+" is not an object!");return e}},function(e,n,i){var l=i(5),t=i(56),r=i(55),o=Object.defineProperty;n.f=i(4)?Object.defineProperty:function(e,n,i){if(l(e),n=r(n,!0),l(i),t)try{return o(e,n,i)}catch(e){}if("get"in i||"set"in i)throw TypeError("Accessors not supported!");return"value"in i&&(e[n]=i.value),e}},function(e,n,i){var l=i(6),t=i(12);e.exports=i(4)?function(e,n,i){return l.f(e,n,t(1,i))}:function(e,n,i){return e[n]=i,e}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var l=o(i(35)),t=o(i(33)),r=o(i(32));function o(e){return e&&e.__esModule?e:{default:e}}n.default=Object.keys(t.default).map(function(e){return new l.default(e,t.default[e],r.default[e])}).reduce(function(e,n){return e[n.name]=n,e},{})},function(e,n,i){var l=i(20)("keys"),t=i(11);e.exports=function(e){return l[e]||(l[e]=t(e))}},function(e,n){e.exports={}},function(e,n){var i=0,l=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++i+l).toString(36))}},function(e,n){e.exports=function(e,n){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:n}}},function(e,n){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,n){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,n){var i=Math.ceil,l=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?l:i)(e)}},function(e,n,i){var l; +/*! + Copyright (c) 2016 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ +/*! + Copyright (c) 2016 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ +!function(){"use strict";var i=function(){function e(){}function n(e,n){for(var i=n.length,l=0;l0?t(l(e),9007199254740991):0}},function(e,n){var i={}.toString;e.exports=function(e){return i.call(e).slice(8,-1)}},function(e,n,i){var l=i(48),t=i(14);e.exports=function(e){return l(t(e))}},function(e,n,i){var l=i(54);e.exports=function(e,n,i){if(l(e),void 0===n)return e;switch(i){case 1:return function(i){return e.call(n,i)};case 2:return function(i,l){return e.call(n,i,l)};case 3:return function(i,l,t){return e.call(n,i,l,t)}}return function(){return e.apply(n,arguments)}}},function(e,n,i){var l=i(1),t=i(7),r=i(3),o=i(11)("src"),a=Function.toString,c=(""+a).split("toString");i(2).inspectSource=function(e){return a.call(e)},(e.exports=function(e,n,i,a){var y="function"==typeof i;y&&(r(i,"name")||t(i,"name",n)),e[n]!==i&&(y&&(r(i,o)||t(i,o,e[n]?""+e[n]:c.join(String(n)))),e===l?e[n]=i:a?e[n]?e[n]=i:t(e,n,i):(delete e[n],t(e,n,i)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[o]||a.call(this)})},function(e,n,i){var l=i(13),t=i(1).document,r=l(t)&&l(t.createElement);e.exports=function(e){return r?t.createElement(e):{}}},function(e,n){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,n,i){var l=i(1),t=i(2),r=i(7),o=i(25),a=i(24),c=function(e,n,i){var y,p,h,x,s=e&c.F,u=e&c.G,d=e&c.S,f=e&c.P,v=e&c.B,g=u?l:d?l[n]||(l[n]={}):(l[n]||{}).prototype,m=u?t:t[n]||(t[n]={}),M=m.prototype||(m.prototype={});for(y in u&&(i=n),i)h=((p=!s&&g&&void 0!==g[y])?g:i)[y],x=v&&p?a(h,l):f&&"function"==typeof h?a(Function.call,h):h,g&&o(g,y,h,e&c.U),m[y]!=h&&r(m,y,x),f&&M[y]!=h&&(M[y]=h)};l.core=t,c.F=1,c.G=2,c.S=4,c.P=8,c.B=16,c.W=32,c.U=64,c.R=128,e.exports=c},function(e,n){e.exports=!1},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var l=Object.assign||function(e){for(var n=1;n0&&void 0!==arguments[0]?arguments[0]:{};if("undefined"==typeof document)throw new Error("`feather.replace()` only works in a browser environment.");var n=document.querySelectorAll("[data-feather]");Array.from(n).forEach(function(n){return function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=function(e){return Array.from(e.attributes).reduce(function(e,n){return e[n.name]=n.value,e},{})}(e),o=i["data-feather"];delete i["data-feather"];var a=r.default[o].toSvg(l({},n,i,{class:(0,t.default)(n.class,i.class)})),c=(new DOMParser).parseFromString(a,"image/svg+xml").querySelector("svg");e.parentNode.replaceChild(c,e)}(n,e)})}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var l,t=i(8),r=(l=t)&&l.__esModule?l:{default:l};n.default=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(console.warn("feather.toSvg() is deprecated. Please use feather.icons[name].toSvg() instead."),!e)throw new Error("The required `key` (icon name) parameter is missing.");if(!r.default[e])throw new Error("No icon matching '"+e+"'. See the complete list of icons at https://feathericons.com");return r.default[e].toSvg(n)}},function(e){e.exports={activity:["pulse","health","action","motion"],airplay:["stream","cast","mirroring"],"alert-circle":["warning"],"alert-octagon":["warning"],"alert-triangle":["warning"],"at-sign":["mention"],award:["achievement","badge"],aperture:["camera","photo"],bell:["alarm","notification"],"bell-off":["alarm","notification","silent"],bluetooth:["wireless"],"book-open":["read"],book:["read","dictionary","booklet","magazine"],bookmark:["read","clip","marker","tag"],briefcase:["work","bag","baggage","folder"],clipboard:["copy"],clock:["time","watch","alarm"],"cloud-drizzle":["weather","shower"],"cloud-lightning":["weather","bolt"],"cloud-rain":["weather"],"cloud-snow":["weather","blizzard"],cloud:["weather"],codepen:["logo"],codesandbox:["logo"],coffee:["drink","cup","mug","tea","cafe","hot","beverage"],command:["keyboard","cmd"],compass:["navigation","safari","travel"],copy:["clone","duplicate"],"corner-down-left":["arrow"],"corner-down-right":["arrow"],"corner-left-down":["arrow"],"corner-left-up":["arrow"],"corner-right-down":["arrow"],"corner-right-up":["arrow"],"corner-up-left":["arrow"],"corner-up-right":["arrow"],"credit-card":["purchase","payment","cc"],crop:["photo","image"],crosshair:["aim","target"],database:["storage"],delete:["remove"],disc:["album","cd","dvd","music"],"dollar-sign":["currency","money","payment"],droplet:["water"],edit:["pencil","change"],"edit-2":["pencil","change"],"edit-3":["pencil","change"],eye:["view","watch"],"eye-off":["view","watch"],"external-link":["outbound"],facebook:["logo"],"fast-forward":["music"],figma:["logo","design","tool"],film:["movie","video"],"folder-minus":["directory"],"folder-plus":["directory"],folder:["directory"],frown:["emoji","face","bad","sad","emotion"],gift:["present","box","birthday","party"],"git-branch":["code","version control"],"git-commit":["code","version control"],"git-merge":["code","version control"],"git-pull-request":["code","version control"],github:["logo","version control"],gitlab:["logo","version control"],global:["world","browser","language","translate"],"hard-drive":["computer","server"],hash:["hashtag","number","pound"],headphones:["music","audio"],heart:["like","love"],"help-circle":["question mark"],hexagon:["shape","node.js","logo"],home:["house"],image:["picture"],inbox:["email"],instagram:["logo","camera"],key:["password","login","authentication"],"life-bouy":["help","life ring","support"],linkedin:["logo"],lock:["security","password"],"log-in":["sign in","arrow"],"log-out":["sign out","arrow"],mail:["email"],"map-pin":["location","navigation","travel","marker"],map:["location","navigation","travel"],maximize:["fullscreen"],"maximize-2":["fullscreen","arrows"],meh:["emoji","face","neutral","emotion"],menu:["bars","navigation","hamburger"],"message-circle":["comment","chat"],"message-square":["comment","chat"],"mic-off":["record"],mic:["record"],minimize:["exit fullscreen"],"minimize-2":["exit fullscreen","arrows"],monitor:["tv"],moon:["dark","night"],"more-horizontal":["ellipsis"],"more-vertical":["ellipsis"],"mouse-pointer":["arrow","cursor"],move:["arrows"],navigation:["location","travel"],"navigation-2":["location","travel"],octagon:["stop"],package:["box"],paperclip:["attachment"],pause:["music","stop"],"pause-circle":["music","stop"],"pen-tool":["vector","drawing"],play:["music","start"],"play-circle":["music","start"],plus:["add","new"],"plus-circle":["add","new"],"plus-square":["add","new"],pocket:["logo","save"],power:["on","off"],radio:["signal"],rewind:["music"],rss:["feed","subscribe"],save:["floppy disk"],search:["find","magnifier","magnifying glass"],send:["message","mail","paper airplane"],settings:["cog","edit","gear","preferences"],shield:["security"],"shield-off":["security"],"shopping-bag":["ecommerce","cart","purchase","store"],"shopping-cart":["ecommerce","cart","purchase","store"],shuffle:["music"],"skip-back":["music"],"skip-forward":["music"],slash:["ban","no"],sliders:["settings","controls"],smile:["emoji","face","happy","good","emotion"],speaker:["music"],star:["bookmark","favorite","like"],sun:["brightness","weather","light"],sunrise:["weather"],sunset:["weather"],tag:["label"],target:["bullseye"],terminal:["code","command line"],"thumbs-down":["dislike","bad"],"thumbs-up":["like","good"],"toggle-left":["on","off","switch"],"toggle-right":["on","off","switch"],trash:["garbage","delete","remove"],"trash-2":["garbage","delete","remove"],triangle:["delta"],truck:["delivery","van","shipping"],twitter:["logo"],umbrella:["rain","weather"],"video-off":["camera","movie","film"],video:["camera","movie","film"],voicemail:["phone"],volume:["music","sound","mute"],"volume-1":["music","sound"],"volume-2":["music","sound"],"volume-x":["music","sound","mute"],watch:["clock","time"],wind:["weather","air"],"x-circle":["cancel","close","delete","remove","times"],"x-octagon":["delete","stop","alert","warning","times"],"x-square":["cancel","close","delete","remove","times"],x:["cancel","close","delete","remove","times"],youtube:["logo","video","play"],"zap-off":["flash","camera","lightning"],zap:["flash","camera","lightning"]}},function(e){e.exports={activity:'',airplay:'',"alert-circle":'',"alert-octagon":'',"alert-triangle":'',"align-center":'',"align-justify":'',"align-left":'',"align-right":'',anchor:'',aperture:'',archive:'',"arrow-down-circle":'',"arrow-down-left":'',"arrow-down-right":'',"arrow-down":'',"arrow-left-circle":'',"arrow-left":'',"arrow-right-circle":'',"arrow-right":'',"arrow-up-circle":'',"arrow-up-left":'',"arrow-up-right":'',"arrow-up":'',"at-sign":'',award:'',"bar-chart-2":'',"bar-chart":'',"battery-charging":'',battery:'',"bell-off":'',bell:'',bluetooth:'',bold:'',"book-open":'',book:'',bookmark:'',box:'',briefcase:'',calendar:'',"camera-off":'',camera:'',cast:'',"check-circle":'',"check-square":'',check:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',"chevrons-down":'',"chevrons-left":'',"chevrons-right":'',"chevrons-up":'',chrome:'',circle:'',clipboard:'',clock:'',"cloud-drizzle":'',"cloud-lightning":'',"cloud-off":'',"cloud-rain":'',"cloud-snow":'',cloud:'',code:'',codepen:'',codesandbox:'',coffee:'',columns:'',command:'',compass:'',copy:'',"corner-down-left":'',"corner-down-right":'',"corner-left-down":'',"corner-left-up":'',"corner-right-down":'',"corner-right-up":'',"corner-up-left":'',"corner-up-right":'',cpu:'',"credit-card":'',crop:'',crosshair:'',database:'',delete:'',disc:'',"dollar-sign":'',"download-cloud":'',download:'',droplet:'',"edit-2":'',"edit-3":'',edit:'',"external-link":'',"eye-off":'',eye:'',facebook:'',"fast-forward":'',feather:'',figma:'',"file-minus":'',"file-plus":'',"file-text":'',file:'',film:'',filter:'',flag:'',"folder-minus":'',"folder-plus":'',folder:'',frown:'',gift:'',"git-branch":'',"git-commit":'',"git-merge":'',"git-pull-request":'',github:'',gitlab:'',globe:'',grid:'',"hard-drive":'',hash:'',headphones:'',heart:'',"help-circle":'',hexagon:'',home:'',image:'',inbox:'',info:'',instagram:'',italic:'',key:'',layers:'',layout:'',"life-buoy":'',"link-2":'',link:'',linkedin:'',list:'',loader:'',lock:'',"log-in":'',"log-out":'',mail:'',"map-pin":'',map:'',"maximize-2":'',maximize:'',meh:'',menu:'',"message-circle":'',"message-square":'',"mic-off":'',mic:'',"minimize-2":'',minimize:'',"minus-circle":'',"minus-square":'',minus:'',monitor:'',moon:'',"more-horizontal":'',"more-vertical":'',"mouse-pointer":'',move:'',music:'',"navigation-2":'',navigation:'',octagon:'',package:'',paperclip:'',"pause-circle":'',pause:'',"pen-tool":'',percent:'',"phone-call":'',"phone-forwarded":'',"phone-incoming":'',"phone-missed":'',"phone-off":'',"phone-outgoing":'',phone:'',"pie-chart":'',"play-circle":'',play:'',"plus-circle":'',"plus-square":'',plus:'',pocket:'',power:'',printer:'',radio:'',"refresh-ccw":'',"refresh-cw":'',repeat:'',rewind:'',"rotate-ccw":'',"rotate-cw":'',rss:'',save:'',scissors:'',search:'',send:'',server:'',settings:'',"share-2":'',share:'',"shield-off":'',shield:'',"shopping-bag":'',"shopping-cart":'',shuffle:'',sidebar:'',"skip-back":'',"skip-forward":'',slack:'',slash:'',sliders:'',smartphone:'',smile:'',speaker:'',square:'',star:'',"stop-circle":'',sun:'',sunrise:'',sunset:'',tablet:'',tag:'',target:'',terminal:'',thermometer:'',"thumbs-down":'',"thumbs-up":'',"toggle-left":'',"toggle-right":'',"trash-2":'',trash:'',trello:'',"trending-down":'',"trending-up":'',triangle:'',truck:'',tv:'',twitter:'',type:'',umbrella:'',underline:'',unlock:'',"upload-cloud":'',upload:'',"user-check":'',"user-minus":'',"user-plus":'',"user-x":'',user:'',users:'',"video-off":'',video:'',voicemail:'',"volume-1":'',"volume-2":'',"volume-x":'',volume:'',watch:'',"wifi-off":'',wifi:'',wind:'',"x-circle":'',"x-octagon":'',"x-square":'',x:'',youtube:'',"zap-off":'',zap:'',"zoom-in":'',"zoom-out":''}},function(e){e.exports={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"}},function(e,n,i){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var l=Object.assign||function(e){for(var n=1;n2&&void 0!==arguments[2]?arguments[2]:[];!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,e),this.name=n,this.contents=i,this.tags=t,this.attrs=l({},o.default,{class:"feather feather-"+n})}return t(e,[{key:"toSvg",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return""+this.contents+""}},{key:"toString",value:function(){return this.contents}}]),e}();n.default=c},function(e,n,i){"use strict";var l=o(i(8)),t=o(i(31)),r=o(i(30));function o(e){return e&&e.__esModule?e:{default:e}}e.exports={icons:l.default,toSvg:t.default,replace:r.default}},function(e,n,i){var l=i(0)("iterator"),t=!1;try{var r=[7][l]();r.return=function(){t=!0},Array.from(r,function(){throw 2})}catch(e){}e.exports=function(e,n){if(!n&&!t)return!1;var i=!1;try{var r=[7],o=r[l]();o.next=function(){return{done:i=!0}},r[l]=function(){return o},e(r)}catch(e){}return i}},function(e,n,i){var l=i(22),t=i(0)("toStringTag"),r="Arguments"==l(function(){return arguments}());e.exports=function(e){var n,i,o;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(i=function(e,n){try{return e[n]}catch(e){}}(n=Object(e),t))?i:r?l(n):"Object"==(o=l(n))&&"function"==typeof n.callee?"Arguments":o}},function(e,n,i){var l=i(38),t=i(0)("iterator"),r=i(10);e.exports=i(2).getIteratorMethod=function(e){if(void 0!=e)return e[t]||e["@@iterator"]||r[l(e)]}},function(e,n,i){"use strict";var l=i(6),t=i(12);e.exports=function(e,n,i){n in e?l.f(e,n,t(0,i)):e[n]=i}},function(e,n,i){var l=i(10),t=i(0)("iterator"),r=Array.prototype;e.exports=function(e){return void 0!==e&&(l.Array===e||r[t]===e)}},function(e,n,i){var l=i(5);e.exports=function(e,n,i,t){try{return t?n(l(i)[0],i[1]):n(i)}catch(n){var r=e.return;throw void 0!==r&&l(r.call(e)),n}}},function(e,n,i){"use strict";var l=i(24),t=i(28),r=i(17),o=i(42),a=i(41),c=i(21),y=i(40),p=i(39);t(t.S+t.F*!i(37)(function(e){Array.from(e)}),"Array",{from:function(e){var n,i,t,h,x=r(e),s="function"==typeof this?this:Array,u=arguments.length,d=u>1?arguments[1]:void 0,f=void 0!==d,v=0,g=p(x);if(f&&(d=l(d,u>2?arguments[2]:void 0,2)),void 0==g||s==Array&&a(g))for(i=new s(n=c(x.length));n>v;v++)y(i,v,f?d(x[v],v):x[v]);else for(h=g.call(x),i=new s;!(t=h.next()).done;v++)y(i,v,f?o(h,d,[t.value,v],!0):t.value);return i.length=v,i}})},function(e,n,i){var l=i(3),t=i(17),r=i(9)("IE_PROTO"),o=Object.prototype;e.exports=Object.getPrototypeOf||function(e){return e=t(e),l(e,r)?e[r]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?o:null}},function(e,n,i){var l=i(1).document;e.exports=l&&l.documentElement},function(e,n,i){var l=i(15),t=Math.max,r=Math.min;e.exports=function(e,n){return(e=l(e))<0?t(e+n,0):r(e,n)}},function(e,n,i){var l=i(23),t=i(21),r=i(46);e.exports=function(e){return function(n,i,o){var a,c=l(n),y=t(c.length),p=r(o,y);if(e&&i!=i){for(;y>p;)if((a=c[p++])!=a)return!0}else for(;y>p;p++)if((e||p in c)&&c[p]===i)return e||p||0;return!e&&-1}}},function(e,n,i){var l=i(22);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==l(e)?e.split(""):Object(e)}},function(e,n,i){var l=i(3),t=i(23),r=i(47)(!1),o=i(9)("IE_PROTO");e.exports=function(e,n){var i,a=t(e),c=0,y=[];for(i in a)i!=o&&l(a,i)&&y.push(i);for(;n.length>c;)l(a,i=n[c++])&&(~r(y,i)||y.push(i));return y}},function(e,n,i){var l=i(49),t=i(19);e.exports=Object.keys||function(e){return l(e,t)}},function(e,n,i){var l=i(6),t=i(5),r=i(50);e.exports=i(4)?Object.defineProperties:function(e,n){t(e);for(var i,o=r(n),a=o.length,c=0;a>c;)l.f(e,i=o[c++],n[i]);return e}},function(e,n,i){var l=i(5),t=i(51),r=i(19),o=i(9)("IE_PROTO"),a=function(){},c=function(){var e,n=i(26)("iframe"),l=r.length;for(n.style.display="none",i(45).appendChild(n),n.src="javascript:",(e=n.contentWindow.document).open(),e.write("