<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Open Source on mm-dev</title>
    <link>https://mm-dev.rocks/tags/open-source/</link>
    <description>Recent content in Open Source on mm-dev</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-gb</language>
    <lastBuildDate>Fri, 05 Apr 2024 12:18:03 +0100</lastBuildDate><atom:link href="https://mm-dev.rocks/tags/open-source/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Vanilla JS</title>
      <link>https://mm-dev.rocks/posts/vanilla-js/</link>
      <pubDate>Fri, 05 Apr 2024 12:18:03 +0100</pubDate>
      <guid>https://mm-dev.rocks/posts/vanilla-js/</guid>
      <description>&lt;h2 id=&#34;toolchain&#34;&gt;Toolchain&lt;/h2&gt;
&lt;p&gt;I enjoy using plain/vanilla JS where possible. For my own projects I try to avoid the sprawl and long build times of NPM.&lt;/p&gt;
&lt;p&gt;I do like to split my code up into separate modules though, and to be able to benefit from bundling/minification etc, for which I use &lt;em&gt;esbuild&lt;/em&gt;. I also want to be able to use &lt;em&gt;SCSS&lt;/em&gt; and &lt;em&gt;JSDoc&lt;/em&gt; for type annotations. So I do allow myself some minimal tooling (the cone and Flake).&lt;/p&gt;
&lt;p&gt;My setup looks like this&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;esbuild---download-a-build&#34;&gt;esbuild - &lt;a href = &#34;https://esbuild.github.io/getting-started/#download-a-build&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;Download a build&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JS bundler&lt;br&gt;
&lt;em&gt;Combine separate modules into a single JS file, minifying/compressing if required&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Tree shaker&lt;br&gt;
&lt;em&gt;Avoid bloat by making sure only those modules/functions which are used get added&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use esbuild for most JS projects, so I installed a standalone build which can be run from anywhere &amp;mdash; but it can also be installed using npm or other methods.&lt;/p&gt;
&lt;h3 id=&#34;sass---how-to-install-sass&#34;&gt;SASS - &lt;a href = &#34;https://sass-lang.com/install&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;How to Install SASS&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Compiler and bundler&lt;br&gt;
&lt;em&gt;Converts SASS/SCSS files into CSS&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;jsdoc---documentation&#34;&gt;JSDoc - &lt;a href = &#34;https://jsdoc.app/&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;Documentation&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Automated documentation creation&lt;br&gt;
&lt;em&gt;HTML docs for your methods, classes and variables will be created based on your code comments&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Type annotations&lt;br&gt;
&lt;em&gt;Comments in your code can tell JSDoc which data types your code expects&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Type annotations you provide (in specially-formatted comments) will be used to automatically create detailed documentation for your project.&lt;/p&gt;
&lt;p&gt;Docs are created as HTML files, with lots of clickable cross-references. The files can be styled based on a templating system and CSS styling.&lt;/p&gt;
&lt;p&gt;Lots of modern editors/IDEs will also use your type annotations to provide type hints and draw attention to potential problems eg if you try to pass an argument of the wrong type you&amp;rsquo;ll get a warning.&lt;/p&gt;
&lt;h3 id=&#34;example-of-project-setup-using-tmuxvim&#34;&gt;Example of Project Setup Using Tmux/Vim&lt;/h3&gt;
&lt;p&gt;I usually write a simple bash script for most projects. I&amp;rsquo;ll run this script when I want to start a session of working on a specific project.&lt;/p&gt;
&lt;p&gt;Below is an example build script (for &lt;a href = &#34;https://mm-dev.rocks/posts/pipe-dream-web-game/&#34; title = &#34;Pipe Dream&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;my &amp;lsquo;Pipe Dream&amp;rsquo; game&lt;/a&gt;) which does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enters the project directory&lt;/li&gt;
&lt;li&gt;Uses &lt;code&gt;tmux&lt;/code&gt; to open a few window panes/splits:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;esbuild&lt;/strong&gt; watching for changes to JS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SASS&lt;/strong&gt; watching for changes to CSS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSDoc&lt;/strong&gt; watching the &lt;code&gt;src&lt;/code&gt; directory (in reality I&amp;rsquo;d often skip this and run it manually on-demand, as it can be slow)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;git&lt;/strong&gt; status, pane left open for commits etc&lt;/li&gt;
&lt;li&gt;A simple &lt;strong&gt;Python server&lt;/strong&gt; so I can test the app in a browser&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Opens a &lt;strong&gt;vim&lt;/strong&gt; session with the relevant source files ready for editing&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Open a JS project using esbuild, SASS and vim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;work_dir&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$HOME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;/pipe-dream/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;tmux&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    new-window -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$work_dir&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;esbuild src/main.js --outfile=www/js/pipe-dream.js --target=es6 --bundle --minify --sourcemap --global-name=PIPEDREAM --format=iife --watch&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    split-window -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$work_dir&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sass --watch src/scss/:www/css/&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    split-window -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$work_dir&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;jsdoc src/ -c jsdoc.config&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    split-window -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$work_dir&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;git status; bash -i&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    split-window -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$work_dir&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;python -m http.server --directory www/&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;select&lt;/span&gt;-layout even-vertical &lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    new-window -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$work_dir&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;vim -S vim.Session&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;vim-configuration&#34;&gt;Vim Configuration&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m one of those Vim people. People say its codebase is bloated but in use it always feels crisp and fast to me. Because of the way you manipulate text objects and leap around the page it somehow feels efficient on low-powered/slow devices, and works particularly well with &lt;a href = &#34;https://mm-dev.rocks/posts/oled-and-eink-4-life/intro/&#34; title = &#34;OLED and E-Ink&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;e-ink devices&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some people argue that they&amp;rsquo;re faster while using Vim than they are in other code editors. I&amp;rsquo;m not sure if I&amp;rsquo;m faster (I might be), but I&amp;rsquo;m from the school of thought that if your bottleneck when writing code is your typing speed, that might not be a good thing.&lt;/p&gt;
&lt;p&gt;More importantly for me, I like the way Vim makes you think about text, as beautifully described in this classic stackoverflow answer &amp;lsquo;&lt;a href = &#34;https://stackoverflow.com/questions/1218390/what-is-your-most-productive-shortcut-with-vim/1220118#1220118&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;Your problem with Vim is that you don&amp;rsquo;t grok vi&lt;/a&gt;&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t like my coding environment to be too noisy or intrusive, but there are some powerful IDE features available nowadays and I don&amp;rsquo;t want to cut off my nose to spite my face.&lt;/p&gt;
&lt;p&gt;Below is some info on some Vim plugins I use to help with JS development.&lt;/p&gt;
&lt;h3 id=&#34;coc-nvim---code-of-conquer-project-repo&#34;&gt;coc-nvim - &lt;a href = &#34;https://github.com/neoclide/coc.nvim&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;Code of Conquer project repo&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Although the &amp;rsquo;nvim&amp;rsquo; stands for Neovim (the popular Vim fork), COC also works very well in modern versions of normal Vim. This plugin allows VSCode-type IDE features, being based on the &lt;a href = &#34;https://en.wikipedia.org/wiki/Language_Server_Protocol&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;Language Server Protocol&lt;/a&gt; standard.&lt;/p&gt;
&lt;p&gt;Very simply, a language server is a tool which understands a specific language, and can be used by your editor/IDE to analyse and give feedback on your code as you write it. It can do things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Syntax highlighting&lt;/li&gt;
&lt;li&gt;Code completion&lt;/li&gt;
&lt;li&gt;Draw attention to errors and give warnings about code&lt;/li&gt;
&lt;li&gt;Help when refactoring code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;COC isn&amp;rsquo;t a language server itself but it allows you to install and maintain whichever servers you need for the languages you use.&lt;/p&gt;
&lt;p&gt;For example the language server I use for JS is &lt;a href = &#34;https://github.com/neoclide/coc-tsserver&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;coc-tsserver&lt;/a&gt;. The &amp;rsquo;ts&amp;rsquo; stands for TypeScript but it works very well with standard JS too. Along with the benefits mentioned above, this language server allows you to use type-checking, like TypeScript but without the compilation step. It also provides documentation and hints on using standard built-in JS methods.&lt;/p&gt;
&lt;p&gt;You annotate your code by providing special comments in &lt;em&gt;JSDoc&lt;/em&gt; syntax. When these comments/annotations are present, COC and the language server give you lots of hints while writing code, and warn you if you try to provide arguments of the wrong type.&lt;/p&gt;
&lt;p&gt;Here is an example (from the &lt;a href = &#34;https://jsdoc.app/howto-es2015-classes&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;official docs&lt;/a&gt;) showing what the &lt;em&gt;JSDoc&lt;/em&gt; syntax looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-JavaScript&#34; data-lang=&#34;JavaScript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/** Class representing a point. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Point&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Create a point.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * @param {number} x - The x value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * @param {number} y - The y value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;constructor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;y&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Get the x value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * @return {number} The x value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;getX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Get the y value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * @return {number} The y value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;getY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Convert a string containing two comma-separated numbers into a point.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * @param {string} str - The string containing two comma-separated numbers.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * @return {Point} A Point object.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kr&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fromString&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Sometimes the help is a little noisy though&amp;hellip;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I love the functionality, but for me it&amp;rsquo;s a bit over-eager, eg if I&amp;rsquo;m half-way through typing a word I don&amp;rsquo;t need a popup telling me the word doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;coc-nvim&lt;/em&gt; does also provide a small symbol at the start of each line where it detects an error or wants to warn about something. So I like to leave the symbol visible, but hide the info popups by default. I add a keyboard shortcut so I can show/hide the explanation of the error/warning when I want to.&lt;/p&gt;
&lt;p&gt;To stop the popups:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-JSON&#34; data-lang=&#34;JSON&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// In ~/.vim/coc-settings.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;diagnostic.enableMessage&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;jump&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To add the show/hide keyboard shortcuts to Vim:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-VimL&#34; data-lang=&#34;VimL&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;&amp;#34; In ~/.vimrc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;nmap&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;silent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;gh&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Plug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;coc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;float&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hide&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;nmap&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;silent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;gl&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Plug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;coc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;diagnostic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;prettier&#34;&gt;Prettier&lt;/h3&gt;
&lt;p&gt;This &lt;a href = &#34;https://prettier.io/&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;opinionated code formatter&lt;/a&gt; formats your code according to some fairly strict rules and has few configurable options (ie it&amp;rsquo;s their way or the highway).&lt;/p&gt;
&lt;p&gt;I think most people find at least some of the rules disagreeable, but the point of this kind of tool is that it does a &amp;lsquo;decent, not perfect&amp;rsquo; job, but provides a standard for formatting and removes the need for discussing, disagreement and wasted time.&lt;/p&gt;
&lt;p&gt;I found it a little annoying at first but then got over myself and prefer now to use it whenever possible.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Pipe Dream (Web Game)</title>
      <link>https://mm-dev.rocks/posts/pipe-dream-web-game/</link>
      <pubDate>Wed, 15 Nov 2023 16:04:45 +0000</pubDate>
      <guid>https://mm-dev.rocks/posts/pipe-dream-web-game/</guid>
      <description>&lt;p&gt;Pipe Dream is a game you can play in your browser &lt;a href = &#34;/pipe-dream&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t need to log in or install anything and of course there are no ads/tracking.&lt;/p&gt;
&lt;p&gt;The game is about as simple as it gets. There are loads of blobs floating about &amp;mdash; avoid some of them and eat the others.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;To control the player&lt;/strong&gt; move your mouse pointer (or drag your finger) over the &lt;strong&gt;control area&lt;/strong&gt; - a rectangle on the right or bottom of the screen (depending on which way around your display is oriented)&lt;/li&gt;
&lt;li&gt;When you hit one of the &lt;strong&gt;avoid blobs&lt;/strong&gt; you lose &lt;strong&gt;health&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Each level gives you a different amount of &lt;strong&gt;time&lt;/strong&gt; to complete it&lt;/li&gt;
&lt;li&gt;To complete a level, eat all the &lt;strong&gt;edible blobs&lt;/strong&gt; before you run out of &lt;strong&gt;time&lt;/strong&gt;, or &lt;strong&gt;health&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul class=&#39;gallery&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_1&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-intro.png&#39; alt=&#39;Intro screen&#39; /&gt;
        &lt;span&gt;Intro screen&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_2&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_2&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-basic.png&#39; alt=&#39;Level BASIC&#39; /&gt;
        &lt;span&gt;Level BASIC&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_3&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_3&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-tooez.png&#39; alt=&#39;Level TOOEZ&#39; /&gt;
        &lt;span&gt;Level TOOEZ&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_4&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_4&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-jungl.png&#39; alt=&#39;Level JUNGL&#39; /&gt;
        &lt;span&gt;Level JUNGL&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_5&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_5&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-mauve.png&#39; alt=&#39;Level MAUVE&#39; /&gt;
        &lt;span&gt;Level MAUVE&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_6&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_6&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-rrred.png&#39; alt=&#39;Level RRRED&#39; /&gt;
        &lt;span&gt;Level RRRED&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_7&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_7&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-mustd.png&#39; alt=&#39;Level MUSTD&#39; /&gt;
        &lt;span&gt;Level MUSTD&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_8&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_8&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-mult1.png&#39; alt=&#39;Level MULT1&#39; /&gt;
        &lt;span&gt;Level MULT1&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_9&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_9&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-mult2.png&#39; alt=&#39;Level MULT2&#39; /&gt;
        &lt;span&gt;Level MULT2&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_10&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_10&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-merng.png&#39; alt=&#39;Level MERNG&#39; /&gt;
        &lt;span&gt;Level MERNG&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_11&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_11&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-dense.png&#39; alt=&#39;Level DENSE&#39; /&gt;
        &lt;span&gt;Level DENSE&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_12&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_12&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-reddd.png&#39; alt=&#39;Level REDDD&#39; /&gt;
        &lt;span&gt;Level REDDD&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_13&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_13&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-lmolv.png&#39; alt=&#39;Level LMOLV&#39; /&gt;
        &lt;span&gt;Level LMOLV&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_14&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_14&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-blrds.png&#39; alt=&#39;Level BLRDS&#39; /&gt;
        &lt;span&gt;Level BLRDS&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_15&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_15&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-gardn.png&#39; alt=&#39;Level GARDN&#39; /&gt;
        &lt;span&gt;Level GARDN&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_16&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_16&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-gnsmk.png&#39; alt=&#39;Level GNSMK&#39; /&gt;
        &lt;span&gt;Level GNSMK&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_17&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_17&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-strry.png&#39; alt=&#39;Level STRRY&#39; /&gt;
        &lt;span&gt;Level STRRY&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_18&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_18&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-pekmn.png&#39; alt=&#39;Level PEKMN&#39; /&gt;
        &lt;span&gt;Level PEKMN&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_19&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_19&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-swarm.png&#39; alt=&#39;Level SWARM&#39; /&gt;
        &lt;span&gt;Level SWARM&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_20&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_20&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-wista.png&#39; alt=&#39;Level WISTA&#39; /&gt;
        &lt;span&gt;Level WISTA&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_21&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_21&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-alien.png&#39; alt=&#39;Level ALIEN&#39; /&gt;
        &lt;span&gt;Level ALIEN&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_22&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_22&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-chpln.png&#39; alt=&#39;Level CHPLN&#39; /&gt;
        &lt;span&gt;Level CHPLN&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_23&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_23&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-oprtn.png&#39; alt=&#39;Level OPRTN&#39; /&gt;
        &lt;span&gt;Level OPRTN&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Qe5h_24&#39; /&gt;
      &lt;label for=&#39;item_Qe5h_24&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/pipe-dream/pd-ntpor.png&#39; alt=&#39;Level NTPOR&#39; /&gt;
        &lt;span&gt;Level NTPOR&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    
    <item>
      <title>dontdillydally (Web App)</title>
      <link>https://mm-dev.rocks/posts/dontdillydally-web-app/</link>
      <pubDate>Tue, 10 Oct 2023 13:17:52 +0100</pubDate>
      <guid>https://mm-dev.rocks/posts/dontdillydally-web-app/</guid>
      <description>&lt;p&gt;&lt;strong&gt;dontdillydally&lt;/strong&gt; helps you track time and money.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aimed at the self-employed&lt;/li&gt;
&lt;li&gt;Focused on simplicity and ease of use&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As this is a web app you don&amp;rsquo;t need to install it, just go to &lt;a href = &#34;https://dontdillydally.app&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;dontdillydally.app&lt;/a&gt; to start using it immediately in your browser.&lt;/p&gt;
&lt;h2 id=&#34;how-to-use&#34;&gt;How to Use&lt;/h2&gt;
&lt;p&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-linnet.png&#34; /&gt;
 &lt;strong&gt;Tap the bird at any time in the app to see the built-in guide&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;
On the left-hand side of the app you will see icons which you can tap to change which section you&amp;rsquo;re on or perform other functions.&lt;/p&gt;






&lt;div class=&#34;expand-all-toggle&#34;&gt;
    &lt;label for=&#34;expandAllCheckbox_Ag43&#34;&gt;&lt;h3 id=&#34;tap-below-to-expand-each-section-and-learn-more-about-it&#34;&gt;Tap below to expand each section and learn more about it:&lt;/h3&gt;
&lt;span&gt;Expand all&lt;/span&gt;
      &lt;input id=&#34;expandAllCheckbox_Ag43&#34; type=&#34;checkbox&#34; onchange=&#34;setChildExpandedStates_Ag43();&#34;/&gt;
    &lt;/label&gt;
  
  &lt;script&gt;
    function setChildExpandedStates_Ag43() {
      var checkbox_el = document.getElementById(&#39;expandAllCheckbox_Ag43&#39;);
      var all = checkbox_el.parentNode.parentNode.getElementsByTagName(&#39;details&#39;);
      for (i = 0; i &lt; all.length; i++) { 
        all[i].open = checkbox_el.checked;
      }
    }
    window.addEventListener(&#39;load&#39;, () =&gt; {
      document.getElementById(&#39;expandAllCheckbox_Ag43&#39;).parentNode.parentNode.classList.add(&#39;js-visible&#39;);
      setChildExpandedStates_Ag43();
    });
  &lt;/script&gt;
&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-worksheet.png&#34; /&gt;
 Worksheet&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;This is the page you&amp;rsquo;ll use the most, it&amp;rsquo;s where you enter your hours worked and any money coming in or going out.&lt;/p&gt;
&lt;p&gt;A worksheet is made of &lt;strong&gt;entries&lt;/strong&gt;. An &lt;strong&gt;entry&lt;/strong&gt; is one of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;time&lt;/strong&gt; spent on a specific job&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;money&lt;/strong&gt; spent on something (expenses)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;money&lt;/strong&gt; coming in (income)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;To add an entry, just tap on the date where you want to add it&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Each &lt;strong&gt;entry&lt;/strong&gt; can have a &lt;strong&gt;client&lt;/strong&gt; and/or a &lt;strong&gt;job&lt;/strong&gt; selected. If you do this you&amp;rsquo;ll then be able to get a &lt;strong&gt;report&lt;/strong&gt; showing you how many hours you worked on that job/client, or how much money you made or spent.&lt;/p&gt;
&lt;p&gt;You can also add &lt;strong&gt;Notes&lt;/strong&gt; to an entry.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;All data fields in an entry are optional, add as much or as little info as you like.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By default when you add a new &lt;strong&gt;entry&lt;/strong&gt; it will be a &lt;strong&gt;time&lt;/strong&gt; entry, and show a &lt;strong&gt;clock icon&lt;/strong&gt; next to it.&lt;/li&gt;
&lt;li&gt;If you tap the clock, the icon changes to a &lt;strong&gt;credit card&lt;/strong&gt; and the entry becomes a &lt;strong&gt;money&lt;/strong&gt; entry.&lt;/li&gt;
&lt;li&gt;To enter an expense, set the value of a money entry to something negative eg &lt;code&gt;-100.00&lt;/code&gt; means you spent 100.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul class=&#39;gallery&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_e8Hs_1&#39; /&gt;
      &lt;label for=&#39;item_e8Hs_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/dontdillydally/time-entry-1.png&#39; alt=&#39;Worksheet: Time entry&#39; /&gt;
        &lt;span&gt;Worksheet: Time entry&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_e8Hs_2&#39; /&gt;
      &lt;label for=&#39;item_e8Hs_2&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_e8Hs_3&#39; /&gt;
      &lt;label for=&#39;item_e8Hs_3&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_e8Hs_4&#39; /&gt;
      &lt;label for=&#39;item_e8Hs_4&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-reports.png&#34; /&gt;
 Reports&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;Here you can get a clear view of everything entered into an entire worksheet, or narrow down on a specific job or client:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Choose a date range from within your worksheet&lt;/li&gt;
&lt;li&gt;Choose a specfic client or job&lt;/li&gt;
&lt;li&gt;Look at only money in/out (hide hours)&lt;/li&gt;
&lt;li&gt;Look at only hours worked (hide money)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then you&amp;rsquo;ll be able to see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How much time you&amp;rsquo;ve spent&lt;/li&gt;
&lt;li&gt;How much you&amp;rsquo;ve earned&lt;/li&gt;
&lt;li&gt;A list of all worksheet entries matching your selection showing eg time, monetary values, notes&lt;/li&gt;
&lt;/ul&gt;
&lt;ul class=&#39;gallery&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_ZVCf_1&#39; /&gt;
      &lt;label for=&#39;item_ZVCf_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/dontdillydally/report-bs-1.png&#39; alt=&#39;Reports: &amp;#39;BendyStraw&amp;#39; job selection&#39; /&gt;
        &lt;span&gt;Reports: &amp;#39;BendyStraw&amp;#39; job selection&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_ZVCf_2&#39; /&gt;
      &lt;label for=&#39;item_ZVCf_2&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/dontdillydally/report-bs-2.png&#39; alt=&#39;Reports: &amp;#39;BendyStraw&amp;#39; job results&#39; /&gt;
        &lt;span&gt;Reports: &amp;#39;BendyStraw&amp;#39; job results&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_ZVCf_3&#39; /&gt;
      &lt;label for=&#39;item_ZVCf_3&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-jobs-clients.png&#34; /&gt;
 Jobs and Clients&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;ul class=&#39;gallery float single-item&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_s9CR_1&#39; /&gt;
      &lt;label for=&#39;item_s9CR_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Jobs&lt;/strong&gt; and &lt;strong&gt;Clients&lt;/strong&gt; can be created and edited here, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A name for the job or client&lt;/li&gt;
&lt;li&gt;Colours (foreground and background) used to represent the job or client in the app&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-settings.png&#34; /&gt;
 Settings&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;/div&gt;







&lt;div class=&#34;expand-all-toggle&#34;&gt;
    &lt;label for=&#34;expandAllCheckbox_eYra&#34;&gt;&lt;h3 id=&#34;the-other-icons-perform-actions-immediately-without-changing-the-page&#34;&gt;The other icons perform actions immediately without changing the page:&lt;/h3&gt;
&lt;span&gt;Expand all&lt;/span&gt;
      &lt;input id=&#34;expandAllCheckbox_eYra&#34; type=&#34;checkbox&#34; onchange=&#34;setChildExpandedStates_eYra();&#34;/&gt;
    &lt;/label&gt;
  
  &lt;script&gt;
    function setChildExpandedStates_eYra() {
      var checkbox_el = document.getElementById(&#39;expandAllCheckbox_eYra&#39;);
      var all = checkbox_el.parentNode.parentNode.getElementsByTagName(&#39;details&#39;);
      for (i = 0; i &lt; all.length; i++) { 
        all[i].open = checkbox_el.checked;
      }
    }
    window.addEventListener(&#39;load&#39;, () =&gt; {
      document.getElementById(&#39;expandAllCheckbox_eYra&#39;).parentNode.parentNode.classList.add(&#39;js-visible&#39;);
      setChildExpandedStates_eYra();
    });
  &lt;/script&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-maximise.png&#34; /&gt;
 Minimise/maximise menu&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;blockquote&gt;
&lt;p&gt;Toggles whether the menu is minimised or maximised.&lt;/p&gt;&lt;/blockquote&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Minimised&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Show only icons&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Maximised&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;Show icons + text labels&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-sync.png&#34; /&gt;
 WebDAV sync&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;This is an experimental feature to sync your data to a WebDAV server so you can keep several devices in sync.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a work-in-progress and not really recommended for most users at this point.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-download.png&#34; /&gt;
 Download data as file&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
Tap this to download all of your data and settings in a file. It will usually end up in your main &lt;code&gt;Downloads&lt;/code&gt; folder.&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-upload.png&#34; /&gt;
 Upload data file&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;If you have a file you previously downloaded you can bring that data back into the app with this button.&lt;/p&gt;
&lt;p&gt;When importing the data you will be given the option to &lt;code&gt;Merge&lt;/code&gt; or &lt;code&gt;Overwrite&lt;/code&gt; your current data.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-email.png&#34; /&gt;
 Email data to a preconfigured address&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
You need to set an email address in &lt;code&gt;Settings&lt;/code&gt; for this option to work.
Your device also needs to know what to do with &lt;code&gt;mailto:&lt;/code&gt; links.&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;img class=&#34;inline-icon&#34; src=&#34;https://mm-dev.rocks/images/dontdillydally/icon-wipe.png&#34; /&gt;
 Wipe your data&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
Completely wipe all of your data and start fresh.&lt;/div&gt;
&lt;/details&gt;


&lt;/div&gt;

&lt;h2 id=&#34;data-storage&#34;&gt;Data Storage&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Automatically saved continually while you work &lt;em&gt;The bird&amp;rsquo;s eye spins when changes are being saved, this is intentionally kept subtle but can be disabled in settings&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Your data is stored inside your browser and stays on your device, it never travels over the internet (unless you decide to send it via email) and is not stored on any servers&lt;/li&gt;
&lt;li&gt;Data uses a simple JSON format, it can be exported/imported as a file to move it between devices&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>BendyStraw (Android App)</title>
      <link>https://mm-dev.rocks/posts/bendystraw-android-app/</link>
      <pubDate>Tue, 10 Oct 2023 13:17:20 +0100</pubDate>
      <guid>https://mm-dev.rocks/posts/bendystraw-android-app/</guid>
      <description>&lt;p&gt;If you don&amp;rsquo;t already know, &lt;a href = &#34;https://newpipe.net/&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;NewPipe&lt;/a&gt; is a privacy-friendly, ad-free Android app for accessing YouTube. It&amp;rsquo;s a great piece of software and I use it all the time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NewPipe&lt;/strong&gt; works without an account. You can subscribe to channels, save playlists and do other useful things, but everything is saved locally on your device (and I love that it works like this).&lt;/p&gt;
&lt;p&gt;I use &lt;strong&gt;NewPipe&lt;/strong&gt; on several Android devices. Over time I&amp;rsquo;ve ended up with different playlists and subscriptions on each device, and sometimes I can&amp;rsquo;t be sure which device I need to use to find a certain song or video. To help with this I made &lt;strong&gt;BendyStraw&lt;/strong&gt;.&lt;/p&gt;
&lt;ul class=&#39;gallery&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_OIkr_1&#39; /&gt;
      &lt;label for=&#39;item_OIkr_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/bendy-straw/bendystraw-grab-3.webp&#39; alt=&#39;Multiple databases in colour-coded tabs&#39; /&gt;
        &lt;span&gt;Multiple databases in colour-coded tabs&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_OIkr_2&#39; /&gt;
      &lt;label for=&#39;item_OIkr_2&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/bendy-straw/bendystraw-grab-1.webp&#39; alt=&#39;Copy streams from one playlist to another&#39; /&gt;
        &lt;span&gt;Copy streams from one playlist to another&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_OIkr_3&#39; /&gt;
      &lt;label for=&#39;item_OIkr_3&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/bendy-straw/bendystraw-grab-2.webp&#39; alt=&#39;Selecting streams to delete, copy or move&#39; /&gt;
        &lt;span&gt;Selecting streams to delete, copy or move&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_OIkr_4&#39; /&gt;
      &lt;label for=&#39;item_OIkr_4&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/bendy-straw/bendystraw-grab-5.webp&#39; alt=&#39;Create new playlists&#39; /&gt;
        &lt;span&gt;Create new playlists&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;BendyStraw&lt;/strong&gt; imports &lt;code&gt;NewPipeData-*.zip&lt;/code&gt; files and lets you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open multiple &lt;code&gt;zip&lt;/code&gt;s at the same time, so you can combine data from several devices&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Delete&lt;/code&gt; &lt;code&gt;Copy&lt;/code&gt; &lt;code&gt;Move&lt;/code&gt; &lt;code&gt;Rename&lt;/code&gt; your custom playlists&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Delete&lt;/code&gt; &lt;code&gt;Copy&lt;/code&gt; &lt;code&gt;Move&lt;/code&gt; streams from one playlist to another&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Delete&lt;/code&gt; &lt;code&gt;Copy&lt;/code&gt; &lt;code&gt;Move&lt;/code&gt; channel subscriptions between databases&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Delete&lt;/code&gt; &lt;code&gt;Copy&lt;/code&gt; &lt;code&gt;Move&lt;/code&gt; remote (bookmarked) playlists&lt;/li&gt;
&lt;li&gt;Re-order playlists, sorting the streams by &lt;code&gt;Title&lt;/code&gt;, &lt;code&gt;Channel&lt;/code&gt; or &lt;code&gt;Length&lt;/code&gt; (just tap the column headings in the tables)&lt;/li&gt;
&lt;li&gt;Streams (audio/video) can be opened directly from &lt;strong&gt;BendyStraw&lt;/strong&gt;, as the URLs are clickable
&lt;ul&gt;
&lt;li&gt;If you set video links (in your Android settings) to open in &lt;strong&gt;NewPipe&lt;/strong&gt; you can make a split-screen view and jump around your playlists&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Export playlist as raw text, for example to be used with &lt;a href = &#34;https://github.com/yt-dlp/yt-dlp&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;yt-dlp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dark/light themes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After editing simply export a new &lt;code&gt;zip&lt;/code&gt; file, then import it back into &lt;strong&gt;NewPipe&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;h3 id=&#34;f-droid&#34;&gt;F-Droid&lt;/h3&gt;
&lt;p&gt;Search for &amp;lsquo;bendystraw&amp;rsquo; (all one word) in the F-Droid app, or find it at &lt;a href = &#34;https://f-droid.org/en/packages/rocks.mm_dev.BendyStraw/&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;https://f-droid.org/en/packages/rocks.mm_dev.BendyStraw/&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;direct-download&#34;&gt;Direct download&lt;/h3&gt;
&lt;p&gt;The apks are also directly available on the Codeberg &lt;a href = &#34;https://codeberg.org/mm-dev/bendy-straw/releases&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;releases page&lt;/a&gt;.&lt;/p&gt;






&lt;div class=&#34;expand-all-toggle&#34;&gt;
    &lt;label for=&#34;expandAllCheckbox_1ZU7&#34;&gt;&lt;h2 id=&#34;how-to-use&#34;&gt;How to Use&lt;/h2&gt;
&lt;span&gt;Expand all&lt;/span&gt;
      &lt;input id=&#34;expandAllCheckbox_1ZU7&#34; type=&#34;checkbox&#34; onchange=&#34;setChildExpandedStates_1ZU7();&#34;/&gt;
    &lt;/label&gt;
  
  &lt;script&gt;
    function setChildExpandedStates_1ZU7() {
      var checkbox_el = document.getElementById(&#39;expandAllCheckbox_1ZU7&#39;);
      var all = checkbox_el.parentNode.parentNode.getElementsByTagName(&#39;details&#39;);
      for (i = 0; i &lt; all.length; i++) { 
        all[i].open = checkbox_el.checked;
      }
    }
    window.addEventListener(&#39;load&#39;, () =&gt; {
      document.getElementById(&#39;expandAllCheckbox_1ZU7&#39;).parentNode.parentNode.classList.add(&#39;js-visible&#39;);
      setChildExpandedStates_1ZU7();
    });
  &lt;/script&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;1-export-your-database-from-newpipe&#34;&gt;1. Export your database from &lt;strong&gt;NewPipe&lt;/strong&gt;&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;NewPipe&lt;/strong&gt; tap &lt;code&gt;Settings&lt;/code&gt; &lt;code&gt;Backup and restore&lt;/code&gt; &lt;code&gt;Export database&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This will create a file on your device with a name like &lt;code&gt;NewPipeData-2023-09-01.zip&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;2-import-it-into-bendystraw&#34;&gt;2. Import it into &lt;strong&gt;BendyStraw&lt;/strong&gt;&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;BendyStraw&lt;/strong&gt;, tap the button with the add/plus icon, and select the file you just exported&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;3-edit-with-bendystraw&#34;&gt;3. Edit with &lt;strong&gt;BendyStraw&lt;/strong&gt;&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;Custom playlists have icons at the top which you can click to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Delete the playlist&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copy the playlist&lt;/strong&gt; to another &lt;code&gt;zip&lt;/code&gt; (you need more than one &lt;code&gt;zip&lt;/code&gt; added to do this)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Export the playlist&lt;/strong&gt; as a plain text file, which for example can be used with &lt;a href = &#34;https://github.com/yt-dlp/yt-dlp&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;yt-dlp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tap on a playlist name to edit&lt;/strong&gt; it, and tap outside (or press return on the keyboard) to finish.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;4-export-from-bendystraw&#34;&gt;4. Export from &lt;strong&gt;BendyStraw&lt;/strong&gt;&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;BendyStraw&lt;/strong&gt; tap the export button (the arrow icon on the bottom-right of the screen)&lt;/li&gt;
&lt;li&gt;This will create a new file named like the original but with &lt;code&gt;-bendy-straw&lt;/code&gt; at the end, so &lt;code&gt;NewPipeData.zip&lt;/code&gt; is saved as &lt;code&gt;NewPipeData-bendy-straw.zip&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;5-import-it-back-into-newpipe&#34;&gt;5. Import it back into &lt;strong&gt;NewPipe&lt;/strong&gt;&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;NewPipe&lt;/strong&gt; tap &lt;code&gt;Settings&lt;/code&gt; &lt;code&gt;Backup and restore&lt;/code&gt; &lt;code&gt;Import database&lt;/code&gt; and select the file you just saved&lt;/li&gt;
&lt;li&gt;After importing the database, &lt;strong&gt;NewPipe&lt;/strong&gt; will ask if you also want to import settings, if you&amp;rsquo;re not sure what this means just tap &amp;lsquo;cancel&amp;rsquo;, your current &lt;strong&gt;NewPipe&lt;/strong&gt; settings will remain unchanged&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;/div&gt;

&lt;h2 id=&#34;json-playlist-import&#34;&gt;JSON Playlist Import&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;BendyStraw&lt;/strong&gt; can import playlists from a JSON file. This is a new and basic feature which has some requirements and limitations.&lt;/p&gt;
&lt;h3 id=&#34;show-the-json-import-button&#34;&gt;Show the JSON Import Button&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;The button is hidden by default&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to the preferences screen (hamburger menu in top-right corner)&lt;/li&gt;
&lt;li&gt;Tick the &amp;lsquo;Show JSON Import Button&amp;rsquo; box&lt;/li&gt;
&lt;li&gt;Open at least 1 database&lt;br&gt;
&lt;em&gt;The button only shows when there is a database open, as it imports the JSON into the currently-opened database&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;limitations&#34;&gt;Limitations&lt;/h3&gt;
&lt;p&gt;We assume that all playlist entries are &lt;strong&gt;YouTube&lt;/strong&gt; streams.&lt;br&gt;
&lt;em&gt;Although &lt;strong&gt;NewPipe&lt;/strong&gt; is able to handle streams from other services too, for now this import feature is just for &lt;strong&gt;YouTube&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The JSON import format has been designed to prefer simplicity over richness of data. This comes with some pros and cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Several stream attributes (eg &amp;lsquo;uploader URL&amp;rsquo;, &amp;lsquo;duration&amp;rsquo;, &amp;lsquo;upload date&amp;rsquo;, &amp;lsquo;view count&amp;rsquo;, &amp;rsquo;thumbnail&amp;rsquo;) are omitted initially&lt;/li&gt;
&lt;li&gt;After import into &lt;strong&gt;NewPipe&lt;/strong&gt;, before the playlist has been played, the above details (attributes) will be missing (so eg the thumbnail will just be a grey blank)&lt;/li&gt;
&lt;li&gt;The first time each stream is started, &lt;strong&gt;NewPipe&lt;/strong&gt; will grab the missing details for the stream and fill in the database&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;requirements&#34;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;JSON playlists will be imported into whichever database is currently open in &lt;strong&gt;BendyStraw&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The general (pseudocode) schema is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;PLAYLIST_NAME&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;ARRAY_OF_STREAMS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;PLAYLIST_NAME&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;ARRAY_OF_STREAMS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;etc...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;playlist_name&#34;&gt;&lt;code&gt;PLAYLIST_NAME&lt;/code&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Is expected to be unique (if it isn&amp;rsquo;t, identically-named lists will be combined into 1 playlist)&lt;/li&gt;
&lt;li&gt;If a playlist with exactly the same name already exists in the target database, entries from the JSON will be appended to that existing database&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;array_of_streams&#34;&gt;&lt;code&gt;ARRAY_OF_STREAMS&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Each stream must be an object with named properties as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I use comments in this explanation but remember comments are not valid JSON &amp;mdash; do not include comments in your JSON&lt;/p&gt;&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// These are required
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;stream_type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;VIDEO_STREAM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// or &amp;#39;AUDIO_STREAM&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Seasonal Affective Disorder&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/watch?v=3RJ5GftYT2c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hidden Valley Bushcraft&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Uploader/channel name,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// These below are optional. NewPipe will update them when the stream is loaded, so they only have meaning on first import before the playlist has been played.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// It&amp;#39;s probably better to omit them but they are allowed if you want to use them.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader_url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/channel/UCB7BPYlL4f5j5R1Y7HUgeVg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Uploader/channel URL 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;duration&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;120&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Length of stream in seconds 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;view_count&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1273621&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Number of times the stream has been viewed on YouTube --- simple number ie no commas, abbreviations etc 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;complete-example-json&#34;&gt;Complete Example JSON&lt;/h4&gt;
&lt;p&gt;Below is some complete sample JSON. If this was imported into a database in &lt;strong&gt;BendyStraw&lt;/strong&gt; it would do one of the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create 2 new playlists (&amp;ldquo;Tech Things&amp;rdquo; and &amp;ldquo;Good Songs&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;Or (if playlists with those names already existed) then the streams would be appended to those existing playlists&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;Tech Things&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;stream_type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;VIDEO_STREAM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Free software, free society: Richard Stallman at TEDxGeneva 2014&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/watch?v=Ag1AKIl_2GM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;TEDx Talks&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader_url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/channel/UCsT0YIqwnpJCM-mx7-gSA4Q&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;stream_type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;VIDEO_STREAM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Shenzhen: The Silicon Valley of Hardware (Full Documentary) | Future Cities&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/watch?v=SGJ5cZnoodY&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Wired UK&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader_url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/@wireduk&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;Good Songs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;stream_type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;VIDEO_STREAM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Aztec Camera - Somewhere In My Heart (Official Music Video)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/watch?v=2w1Q8ZkXZ1Q&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;RHINO&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader_url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/channel/UCWEtnEiVwUy7mwFeshyAWLA&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;stream_type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;VIDEO_STREAM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Imagine Dragons - Thunder&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/watch?v=fKopy74weus&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ImagineDragonsVEVO&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader_url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/channel/UCpx_k19S2vUutWUUM9qmXEg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;stream_type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;VIDEO_STREAM&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;𝑰𝒕&amp;#39;𝒔 𝑨 𝑯𝒆𝒂𝒓𝒕𝒂𝒄𝒉𝒆 -Bonnie Tyler (Cover by Yhuan) #gutomversion #hitback #goodvibestambayan #yhuan&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/watch?v=AQCm7VWyg-U&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Yhuan Official&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploader_url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.youtube.com/channel/UCDxVjSFhfiPGispcK9o0qzw&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class=&#34;expand-all-toggle&#34;&gt;
    &lt;label for=&#34;expandAllCheckbox_fJI7&#34;&gt;&lt;h2 id=&#34;faq&#34;&gt;FAQ&lt;/h2&gt;
&lt;span&gt;Expand all&lt;/span&gt;
      &lt;input id=&#34;expandAllCheckbox_fJI7&#34; type=&#34;checkbox&#34; onchange=&#34;setChildExpandedStates_fJI7();&#34;/&gt;
    &lt;/label&gt;
  
  &lt;script&gt;
    function setChildExpandedStates_fJI7() {
      var checkbox_el = document.getElementById(&#39;expandAllCheckbox_fJI7&#39;);
      var all = checkbox_el.parentNode.parentNode.getElementsByTagName(&#39;details&#39;);
      for (i = 0; i &lt; all.length; i++) { 
        all[i].open = checkbox_el.checked;
      }
    }
    window.addEventListener(&#39;load&#39;, () =&gt; {
      document.getElementById(&#39;expandAllCheckbox_fJI7&#39;).parentNode.parentNode.classList.add(&#39;js-visible&#39;);
      setChildExpandedStates_fJI7();
    });
  &lt;/script&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;whats-in-the-zip-files&#34;&gt;What&amp;rsquo;s in the &lt;code&gt;zip&lt;/code&gt; files?&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;&lt;strong&gt;NewPipe&lt;/strong&gt; exports a &lt;code&gt;zip&lt;/code&gt; file, containing 2 files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;newpipe.db&lt;/code&gt;: A database which has all the info &lt;strong&gt;BendyStraw&lt;/strong&gt; uses, such as your playlists and channel subscriptions, plus other things like your watch history&lt;/li&gt;
&lt;li&gt;&lt;code&gt;newpipe.settings&lt;/code&gt;: Your &lt;strong&gt;NewPipe&lt;/strong&gt; settings and preferences&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For simplicity &lt;strong&gt;BendyStraw&lt;/strong&gt; sometimes refers to the &lt;code&gt;zip&lt;/code&gt; file as the database, because that&amp;rsquo;s the file &lt;strong&gt;NewPipe&lt;/strong&gt; works with for imports/exports.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;is-my-data-private&#34;&gt;Is my data private?&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
Yes! This is important to me as a developer. &lt;strong&gt;BendyStraw&lt;/strong&gt; only works with the tables in the database which it requires to let you do your editing. It doesn&amp;rsquo;t look into other things like your settings or watch history and it doesn&amp;rsquo;t send your data to any servers or share it with anybody. There&amp;rsquo;s no tracking and no adverts or anything like that.&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;what-happens-to-my-newpipe-settings&#34;&gt;What happens to my &lt;strong&gt;NewPipe&lt;/strong&gt; settings?&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;&lt;strong&gt;BendyStraw&lt;/strong&gt; doesn&amp;rsquo;t look inside them or change them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you edit &lt;code&gt;zip&lt;/code&gt;s from multiple devices, or old/archived &lt;code&gt;zip&lt;/code&gt;s, be aware that your new &lt;code&gt;zip&lt;/code&gt; will have the settings from whichever original file you opened. &lt;em&gt;So be careful not to overwrite settings with an old version.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;When you import your new &lt;code&gt;zip&lt;/code&gt; into &lt;strong&gt;NewPipe&lt;/strong&gt; the simplest thing to do is just tap &amp;lsquo;cancel&amp;rsquo; when it asks if you want to also import settings.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;ive-opened-multiple-databases-but-dont-see-enough-tabs&#34;&gt;I&amp;rsquo;ve opened multiple databases but don&amp;rsquo;t see enough tabs&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;The tabs can scroll off the edge of the screen, swipe left/right on the tab bar to see any tabs which have overflowed.&lt;/p&gt;
&lt;p&gt;You can also swipe left or right on any blank area to switch tabs.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;how-do-i-use-an-exported-text-playlist&#34;&gt;How do I use an exported text playlist?&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;If you have &lt;a href = &#34;https://github.com/yt-dlp/yt-dlp&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;yt-dlp&lt;/a&gt; installed, you can batch download all of the files from the playlist like so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;BendyStraw&lt;/strong&gt; locate the playlist and tap the &amp;rsquo;export&amp;rsquo; button&lt;/li&gt;
&lt;li&gt;Check the dialog to see where the text file will be saved&lt;/li&gt;
&lt;li&gt;In your terminal run &lt;code&gt;yt-dlp --batch-file [path_to_text_file.txt]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more info check out &lt;a href = &#34;https://github.com/yt-dlp/yt-dlp&#34; target = &#34;_blank&#34; rel = &#34;nofollow noopener noreferrer&#34;&gt;the yt-dlp github&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;

&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;can-i-export-an-m3u-playlist&#34;&gt;Can I export an M3U playlist?&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;I originally did build this functionality, only to find that links to eg YouTube streams no longer work in &lt;code&gt;m3u&lt;/code&gt; playlists. This is true for the players I tested and to the best of my knowledge.&lt;/p&gt;
&lt;p&gt;If I&amp;rsquo;m wrong about this, you have some other relevant info, or would like to see some other export format, please let me know.&lt;em class=&#34;star&#34;&gt;*&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d be happy to revisit this if it&amp;rsquo;s useful.&lt;/p&gt;
&lt;p&gt;&lt;em class=&#34;star&#34;&gt;*&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;big-button&#34; href=&#34;mailto:hello@mm-dev.rocks&#34;&gt;&lt;a &gt;hello@mm-dev.rocks&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;why-do-i-need-to-grant-all-files-access-permission-in-android-13&#34;&gt;Why do I need to grant &amp;lsquo;all files access&amp;rsquo; permission in Android 13?&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;&lt;strong&gt;BendyStraw&lt;/strong&gt; needs to work with files from a different app (&lt;strong&gt;NewPipe&lt;/strong&gt;). The way permissions have changed in Android 13 makes this complicated, as document files (ie non-media files such as &lt;code&gt;.zip&lt;/code&gt;) can only be read from and written to the directory belonging to the app that created them. The only simple way to keep the app easy to use is to ask for these permissions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BendyStraw&lt;/strong&gt; has no interest in doing anything unexpected to your filesystem. The code is open source, so any developer can check to make sure that it only does what it says it does.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;/div&gt;

</description>
    </item>
    
    <item>
      <title>Holistik: Activity Overview (Garmin Watch App)</title>
      <link>https://mm-dev.rocks/posts/holistik-garmin-app/</link>
      <pubDate>Tue, 10 Oct 2023 13:17:08 +0100</pubDate>
      <guid>https://mm-dev.rocks/posts/holistik-garmin-app/</guid>
      <description>&lt;p&gt;Garmin watches (such as the Fenix 5 Plus which I have) gather a lot of info about your exercise activity, but to see it you need to log in to your Connect IQ account in their app or a browser, using a separate device such as a phone or laptop.&lt;/p&gt;
&lt;p&gt;One of the things I like most about this watch is that despite the usual ecosystem tie-ins, you can do most things with it offline, even including GPS navigation as it stores its own offline maps and has a GPS device built-in (unlike lots of other devices that depend on beign BlueTooth-linked to your phone for GPS features). The only sore point for me is the lack of a visual overview of activities, without logging in to Connect IQ.&lt;/p&gt;
&lt;p&gt;This app is my solution. Get a birds-eye view at different zoom levels (days, weeks or months at a time) - great when your device is offline and you want to check your activity levels at a glance!&lt;/p&gt;
&lt;ul class=&#39;gallery&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_HGaY_1&#39; /&gt;
      &lt;label for=&#39;item_HGaY_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/holistik-grab-2.png&#39; alt=&#39;Days&#39; /&gt;
        &lt;span&gt;Days&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_HGaY_2&#39; /&gt;
      &lt;label for=&#39;item_HGaY_2&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/holistik-grab-1.png&#39; alt=&#39;Weeks&#39; /&gt;
        &lt;span&gt;Weeks&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_HGaY_3&#39; /&gt;
      &lt;label for=&#39;item_HGaY_3&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/holistik-grab-3.png&#39; alt=&#39;Months&#39; /&gt;
        &lt;span&gt;Months&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;how-to-use&#34;&gt;How to Use&lt;/h2&gt;
&lt;h3 id=&#34;day-colours&#34;&gt;Day Colours&lt;/h3&gt;
&lt;p&gt;Days (squares) are coloured according to how many activities you recorded that day, plus time spent or distance covered:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Activity level&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Warm themes&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Cool themes&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Some&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #FFAA00&#34;&gt;&lt;span&gt;Yellow&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #00FFCC&#34;&gt;&lt;span&gt;Light Green&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Moderate&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #FF0000&#34;&gt;&lt;span&gt;Red          &lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #00FF00&#34;&gt;&lt;span&gt;Mid Green  &lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;High&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #4B0000&#34;&gt;&lt;span&gt;Dark Red     &lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #023E02&#34;&gt;&lt;span&gt;Dark Green &lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Some other days are coloured to help you see what&amp;rsquo;s what. Where the year or month is written in text, the same colours will also be used.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;Day type&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Warm, Dark theme&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Cool, Dark theme&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Warm, Light theme&lt;/th&gt;
          &lt;th style=&#34;text-align: left&#34;&gt;Cool, Light theme&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;No activities recorded&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #AAAAAA&#34;&gt;&lt;span&gt;Light Grey&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #AAAAAA&#34;&gt;&lt;span&gt;Light Grey&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #AAAAAA&#34;&gt;&lt;span&gt;Light Grey&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #AAAAAA&#34;&gt;&lt;span&gt;Light Grey&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Weekends&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #555555&#34;&gt;&lt;span&gt;Dark Grey&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #555555&#34;&gt;&lt;span&gt;Dark Grey&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #555555&#34;&gt;&lt;span&gt;Dark Grey&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #555555&#34;&gt;&lt;span&gt;Dark Grey&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;First of the month&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #000088&#34;&gt;&lt;span&gt;Dark Blue&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #ff5500&#34;&gt;&lt;span&gt;Orange&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #000044&#34;&gt;&lt;span&gt;Navy&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #662200&#34;&gt;&lt;span&gt;Brown&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;First day of the year&lt;/strong&gt;&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #440166&#34;&gt;&lt;span&gt;Purple&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #FFAA00&#34;&gt;&lt;span&gt;Yellow&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #662200&#34;&gt;&lt;span&gt;Brown&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
          &lt;td style=&#34;text-align: left&#34;&gt;&lt;span class=&#34;chip&#34; style=&#34;background-color: #4B0000&#34;&gt;&lt;span&gt;Dark Red&lt;/span&gt;&lt;/span&gt;
&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;watch-button-functions&#34;&gt;Watch Button Functions&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Start&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;&lt;em&gt;Change view&lt;/em&gt; (Days/Weeks/Months)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Up&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;&lt;em&gt;Previous&lt;/em&gt; day/week/month&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Down&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;&lt;em&gt;Next&lt;/em&gt; day/week/month&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Menu&lt;/strong&gt; &lt;small class=&#34;special&#34;&gt;
press + hold &lt;strong&gt;Up&lt;/strong&gt;&lt;/small&gt;
&lt;/td&gt;
          &lt;td&gt;Show &lt;em&gt;Settings&lt;/em&gt; screen&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;views&#34;&gt;Views&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Days&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Details of individual activities for the selected day eg &amp;ldquo;5:30am Train 32mins&amp;rdquo;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;/td&gt;
          &lt;td&gt;&lt;ul class=&#39;gallery&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_tdEK_1&#39; /&gt;
      &lt;label for=&#39;item_tdEK_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/days-warm-dark.png&#39; alt=&#39;View: Days, Theme: Warm&#39; /&gt;
        &lt;span&gt;View: Days, Theme: Warm&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_tdEK_2&#39; /&gt;
      &lt;label for=&#39;item_tdEK_2&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/days-cool-dark.png&#39; alt=&#39;View: Days, Theme: Cool&#39; /&gt;
        &lt;span&gt;View: Days, Theme: Cool&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Weeks&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Shows combined activity totals for the selected week eg &amp;ldquo;Train 3hrs&amp;rdquo;, &amp;ldquo;Walk 7hrs 21 miles&amp;rdquo;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;/td&gt;
          &lt;td&gt;&lt;ul class=&#39;gallery&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_f2eA_1&#39; /&gt;
      &lt;label for=&#39;item_f2eA_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/weeks-warm-dark.png&#39; alt=&#39;View: Weeks, Theme: Warm&#39; /&gt;
        &lt;span&gt;View: Weeks, Theme: Warm&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_f2eA_2&#39; /&gt;
      &lt;label for=&#39;item_f2eA_2&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/weeks-cool-dark.png&#39; alt=&#39;View: Weeks, Theme: Cool&#39; /&gt;
        &lt;span&gt;View: Weeks, Theme: Cool&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Months&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Shows combined totals just like the weeks view &lt;small class=&#34;special&#34;&gt;
Depending on device performance and number of recorded activities, it can take a second or so to jump from month to month. Buttons remain active during this time (eg if you&amp;rsquo;re on December and you press UP 6 times you&amp;rsquo;ll still land on June, it might just take a moment to catch up).&lt;/small&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;/td&gt;
          &lt;td&gt;&lt;ul class=&#39;gallery&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Ctji_1&#39; /&gt;
      &lt;label for=&#39;item_Ctji_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/months-warm-dark.png&#39; alt=&#39;View: Months, Theme: Warm&#39; /&gt;
        &lt;span&gt;View: Months, Theme: Warm&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_Ctji_2&#39; /&gt;
      &lt;label for=&#39;item_Ctji_2&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/months-cool-dark.png&#39; alt=&#39;View: Months, Theme: Cool&#39; /&gt;
        &lt;span&gt;View: Months, Theme: Cool&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;






&lt;div class=&#34;expand-all-toggle&#34;&gt;
    &lt;label for=&#34;expandAllCheckbox_NnWj&#34;&gt;&lt;h3 id=&#34;hints-and-tips&#34;&gt;Hints and Tips&lt;/h3&gt;
&lt;span&gt;Expand all&lt;/span&gt;
      &lt;input id=&#34;expandAllCheckbox_NnWj&#34; type=&#34;checkbox&#34; onchange=&#34;setChildExpandedStates_NnWj();&#34;/&gt;
    &lt;/label&gt;
  
  &lt;script&gt;
    function setChildExpandedStates_NnWj() {
      var checkbox_el = document.getElementById(&#39;expandAllCheckbox_NnWj&#39;);
      var all = checkbox_el.parentNode.parentNode.getElementsByTagName(&#39;details&#39;);
      for (i = 0; i &lt; all.length; i++) { 
        all[i].open = checkbox_el.checked;
      }
    }
    window.addEventListener(&#39;load&#39;, () =&gt; {
      document.getElementById(&#39;expandAllCheckbox_NnWj&#39;).parentNode.parentNode.classList.add(&#39;js-visible&#39;);
      setChildExpandedStates_NnWj();
    });
  &lt;/script&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;to-maximise-usage-of-space-on-round-screens-days-flow-in-a-snaking-pattern&#34;&gt;To maximise usage of space on round screens, days flow in a &amp;lsquo;snaking&amp;rsquo; pattern&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;ul class=&#39;gallery float single-item&#39;&gt;&lt;li&gt;
      &lt;input type=&#39;checkbox&#39; id=&#39;item_6viV_1&#39; /&gt;
      &lt;label for=&#39;item_6viV_1&#39; aria-label=&#39;Expand image&#39; tabindex=&#39;0&#39;&gt;&lt;img src=&#39;https://mm-dev.rocks/images/holistik/past-future.png&#39; alt=&#39;Past &amp;gt; Future Days&#39; /&gt;
        &lt;span&gt;Past &amp;gt; Future Days&lt;/span&gt;&lt;/label&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip;like an airport queue.&lt;/p&gt;
&lt;p&gt;Earlier days are to the left, later to the right.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;the-day-you-select-in-days-view-affects-how-the-weeksmonths-are-centred-in-the-other-views&#34;&gt;The day you select in &lt;em&gt;Days View&lt;/em&gt; affects how the weeks/months are centred in the other views&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;In Days View if you select a &lt;em&gt;Wednesday&lt;/em&gt;, then Weeks View will be centred around &lt;em&gt;Wednesdays&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;In Days View if you select the &lt;em&gt;17th&lt;/em&gt;, then Months View will be centred around the &lt;em&gt;17th&lt;/em&gt; of each month&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;holistik-only-uses-activities-which-have-been-recordedstored-on-your-watch&#34;&gt;Holistik only uses activities which have been recorded/stored on your watch&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&amp;mdash; so not heart rate, steps etc.&lt;/div&gt;
&lt;/details&gt;


&lt;details&gt;
&lt;summary&gt;&lt;span&gt;&lt;h4 id=&#34;holistik-runs-entirely-offline&#34;&gt;Holistik runs entirely offline&lt;/h4&gt;
&lt;/span&gt;&lt;/summary&gt;

&lt;div&gt;
&lt;p&gt;&amp;hellip;using activity data which is already stored on your watch.&lt;/p&gt;
&lt;p&gt;It does not store or send your information anywhere.&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;


&lt;/div&gt;

&lt;h2 id=&#34;settings&#34;&gt;Settings&lt;/h2&gt;
&lt;p&gt;Press and hold &lt;em&gt;Menu&lt;/em&gt; while the app is running to change settings:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Theme&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Light, Warm&lt;/td&gt;
          &lt;td&gt;Dark, Warm&lt;/td&gt;
          &lt;td&gt;Light, Cool&lt;/td&gt;
          &lt;td&gt;Dark, Cool&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Font&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Small&lt;/td&gt;
          &lt;td&gt;Medium&lt;/td&gt;
          &lt;td&gt;Large&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Date Format&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;dd/mm&lt;/td&gt;
          &lt;td&gt;mm/dd&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Difficulty&lt;/strong&gt; [1]&lt;/td&gt;
          &lt;td&gt;Basic&lt;/td&gt;
          &lt;td&gt;Intermediate&lt;/td&gt;
          &lt;td&gt;Advanced&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Duration Display&lt;/strong&gt; [2]&lt;/td&gt;
          &lt;td&gt;Basic&lt;/td&gt;
          &lt;td&gt;Intermediate&lt;/td&gt;
          &lt;td&gt;Advanced&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Duration Display&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Hours and Fractions&lt;/td&gt;
          &lt;td&gt;Minutes&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Initial View&lt;/strong&gt; [3]&lt;/td&gt;
          &lt;td&gt;Basic&lt;/td&gt;
          &lt;td&gt;Intermediate&lt;/td&gt;
          &lt;td&gt;Advanced&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Duration Display&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Months&lt;/td&gt;
          &lt;td&gt;Weeks&lt;/td&gt;
          &lt;td&gt;Days&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Text Display&lt;/strong&gt; [4]&lt;/td&gt;
          &lt;td&gt;Basic&lt;/td&gt;
          &lt;td&gt;Intermediate&lt;/td&gt;
          &lt;td&gt;Advanced&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Duration Display&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Show Dates&lt;/td&gt;
          &lt;td&gt;Show Activity Details&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;small class=&#34;special&#34;&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;[1] &lt;strong&gt;Difficulty&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Change according to your fitness level and the calculations will adjust so the coloured days make sense for you&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;[2] &lt;strong&gt;Duration Display&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Activity durations can be shown in minutes (&amp;lsquo;73mins&amp;rsquo;) or to the nearest fraction of an hour (&amp;lsquo;1 1/4hrs&amp;rsquo;)&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;[3] &lt;strong&gt;Initial View&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;View to display when first opening the app&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;[4] &lt;strong&gt;Text Display&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;If &amp;lsquo;Show Dates&amp;rsquo; is disabled dates will still be shown temporarily while you move backwards and forwards, then disappear after a second or two&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/small&gt;

&lt;h2 id=&#34;app-permissions&#34;&gt;App Permissions&lt;/h2&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;&lt;/th&gt;
          &lt;th&gt;&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;User Profile&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Allows the app to read the activity data before displaying it&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;&lt;strong&gt;Persisted Content&lt;/strong&gt;&lt;/td&gt;
          &lt;td&gt;Allows the app to store/read your settings detailed above&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</description>
    </item>
    
  </channel>
</rss>
