Removed from brookjs

const child$s = new WeakMap();
const getChildStream = (stream$, id) => {
let childs = child$s.get(stream$);
if (!childs) {
child$s.set(stream$, childs = {});
}
if (childs[id]) {
return childs[id];
}
return childs[id] = stream$.map(props => props.dict[id]);
};
const orderMatches = (prev, next) => prev.order === next.order;
const id = x => x;
export default function loop(mapper, callback) {
if (callback == null) {
callback = mapper;
mapper = id;
}
return stream$ => {
const src$ = stream$.map(mapper);
return src$.skipDuplicates(orderMatches)
.map(props => props.order.map(id => callback(getChildStream(src$, id), id)));
};
}
loop.js
import Kefir from 'kefir';
import * as PropTypes from 'prop-types';
const spyOn = (s$, validator, propName, componentName, name) => {
if (s$._alive) {
const handler = (event) => {
if (event.type === 'value') {
PropTypes.checkPropTypes(validator, event.value, 'prop', componentName);
}
};
if (!s$._spyHandlers) {
s$._spyHandlers = [];
}
s$._spyHandlers.push({ name, handler });
s$._dispatcher.addSpy(handler);
if (s$._currentEvent) {
handler(s$._currentEvent);
}
}
};
export default function observableOfValidator(valueValidator, name = 'observableOf') {
const validator = function observableOf(props, propName, componentName) {
const propValue = props[propName];
if (propValue == null) {
return null;
}
if (!(propValue instanceof Kefir.Observable)) {
return new TypeError(`${componentName}: ${propName} must be an Observable, got "${typeof propValue}"`);
}
spyOn(propValue, valueValidator, propName, componentName, name);
return null;
};
validator.isRequired = function andIsRequired(props, propName, componentName) {
const propValue = props[propName];
if (!(propValue instanceof Kefir.Observable)) {
return new TypeError(`${componentName}: ${propName} must be an Observable, got "${typeof propValue}"`);
}
spyOn(propValue, valueValidator, propName, componentName, name);
return null;
};
return wrapValidator(validator, name);
}
function wrapValidator(validator, typeName, typeChecker = null) {
return Object.assign(validator.bind(), {
typeName,
typeChecker,
isRequired: Object.assign(validator.isRequired.bind(), {
typeName,
typeChecker,
typeRequired: true,
}),
});
}
observableOf.js

Sync ownCloud bookmarks to Pinboard

import os
import requests
from bs4 import BeautifulSoup
from termcolor import cprint
from dotenv import load_dotenv
class Hydrator(object):
def __init__(self):
self.soups = {}
def title(self, url):
soup = self._get_soup(url)
title = soup.title.string
if title == "":
cprint(f"Url provided as title for {url}", "white", "on_blue")
title = url
return title
def description(self, url):
soup = self._get_soup(url)
meta = soup.find_all("meta")
for tag in meta:
if (
"name" in tag.attrs.keys()
and tag.attrs["name"].strip().lower() == "description"
):
content = tag.attrs.get("content")
if content is None:
content = tag.attrs.get("value")
if content is None:
cprint(f"No content found", "red")
print(tag.attrs.keys())
else:
return content
cprint(f"No description found for {url}", "white", "on_blue")
return ""
def _get_soup(self, url):
soup = self.soups.get(url)
if soup is None:
response = requests.get(url)
soup = self.soups[url] = BeautifulSoup(response.content, "lxml")
return soup
hydrate = Hydrator()
def get_bookmark_from_pinboard(url):
response = requests.get(
url="https://api.pinboard.in/v1/posts/get",
params={
"url": url,
"auth_token": os.getenv("PINBOARD_AUTH_TOKEN"),
"format": "json",
},
)
posts = response.json()["posts"]
return posts[0] if len(posts) == 1 else None
def hydrate_bookmark(bookmark):
title = bookmark["title"]
url = bookmark["url"]
description = bookmark["description"]
if title == url or title == "":
title = hydrate.title(url)
if description == url or description == "":
description = hydrate.description(url)
return {
"url": url,
"title": title,
"description": description,
"tags": bookmark["tags"],
}
def add_bookmark_to_pinboard(bookmark):
response = requests.get(
url="https://api.pinboard.in/v1/posts/add",
params={
"auth_token": os.getenv("PINBOARD_AUTH_TOKEN"),
"format": "json",
"url": bookmark["url"],
# actually title
"description": bookmark["title"],
# actually description
"extended": bookmark["description"],
"tags": ",".join(bookmark["tags"]),
},
)
body = response.json()
return body["result_code"] == "done"
def process_bookmark(bookmark):
url = bookmark["url"]
pinboard_bookmark = get_bookmark_from_pinboard(url)
# Add only if we don't find the bookmark in pinboard.
if pinboard_bookmark is None:
hydrated = hydrate_bookmark(bookmark)
success = add_bookmark_to_pinboard(hydrated)
if success:
cprint(f"Successfully added {url} to pinboard", "green")
else:
cprint(f"Error adding {url} to pinboard", "red")
else:
cprint(f"Url {url} found in Pinboard. Skipping.", "yellow")
def send_request(page=0):
try:
response = requests.get(
url=f'https://{os.getenv("OWNCLOUD_DOMAIN")}/index.php/apps/bookmarks/bookmark',
params={"type": "bookmark", "page": page},
headers={
"Cookie": os.getenv("OWNCLOUD_COOKIE"),
"requesttoken": os.getenv("OWNCLOUD_REQUEST_TOKEN"),
},
)
body = response.json()
status = body["status"]
if status == "success":
data = body["data"]
for bookmark in data:
process_bookmark(bookmark)
if len(data) != 0:
send_request(page + 1)
except requests.exceptions.RequestException as err:
cprint(f"Request failed: {err.request.url}", "red")
if __name__ == "__main__":
load_dotenv()
send_request()
__main__.py
PINBOARD_AUTH_TOKEN=username:token
OWNCLOUD_DOMAIN=your.owncloud.domain.com
OWNCLOUD_COOKIE=Get this from the network tab of the bookmarks page
OWNCLOUD_REQUEST_TOKEN=Also from the network tab
.env

Update Array Hack

const arr = [1, 2, 3];
const newArr = Array.from({ ...arr, 1: 3, length: arr.length });
console.log(newArr); // [1, 3, 3]
update-array.js
const arr = [1, 2, 3];
const newObj = { ...arr };
console.log(newObj); // {0: 1, 1: 2, 2: 3}
spread-array.js

Trellis Gatsby Configuration

diff --git a/deploy-hooks/build-before.yml b/deploy-hooks/build-before.yml
--- a/deploy-hooks/build-before.yml
+++ b/deploy-hooks/build-before.yml
+- name: Install npm dependencies
+ command: npm ci
+ connection: local
+ args:
+ chdir: "~/path/to/gatsby"
+
+- name: Compile assets for production
+ command: npm run build
+ connection: local
+ args:
+ chdir: "~/path/to/gatsby"
+
+- name: Copy production assets
+ synchronize:
+ src: "~/path/to/gatsby/public"
+ dest: "{{ deploy_helper.new_release_path }}"
+ group: no
+ owner: no
+ rsync_opts: --chmod=Du=rwx,--chmod=Dg=rx,--chmod=Do=rx,--chmod=Fu=rw,--chmod=Fg=r,--chmod=Fo=r
deploy-hooks/build-before.yml
diff --git a/group_vars/development/wordpress_sites.yml b/group_vars/development/wordpress_sites.yml
--- a/group_vars/development/wordpress_sites.yml
+++ b/group_vars/development/wordpress_sites.yml
@@ -8,6 +8,7 @@ wordpress_sites:
- canonical: domain.test
local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
admin_email: admin@domain.test
+ nginx_wordpress_site_conf: templates/domain.com.conf.j2
multisite:
enabled: false
ssl:
diff --git a/group_vars/production/wordpress_sites.yml b/group_vars/production/wordpress_sites.yml
index 48b69b9..99d775f 100644
--- a/group_vars/production/wordpress_sites.yml
+++ b/group_vars/production/wordpress_sites.yml
@@ -9,6 +9,7 @@ wordpress_sites:
local_path: ../site # path targeting local Bedrock site directory (relative to Ansible root)
repo: git@bitbucket.org:repo/domain.git # replace with your Git repo URL
branch: master
+ nginx_wordpress_site_conf: templates/domain.com.conf.j2
multisite:
enabled: false
ssl:
group_vars/development/wordpress_sites.yml
diff --git a/templates/domain.com.conf.j2 b/templates/domain.com.conf.j2
+++ b/templates/domain.com.conf.j2
+{% extends 'roles/wordpress-setup/templates/domain.com.conf.j2' %}
+
+{% block location_primary -%}
+location /wp-json {
+ try_files $uri $uri/ /index.php?$args;
+ }
+ location /wp/ {
+ try_files $uri $uri/ /wp/wp-admin/;
+ }
+ location / {
+ root {{ www_root }}/{{ item.key }}/{{ item.value.current_path | default('current') }}/public;
+ error_page 404 /404.html;
+ }
+{% endblock %}
templates/wordpress-site.conf.j2

Get List of Commits

const { findGitRepos, getCommitsFromRepos } = require ('./gitutils');
findGitRepos(['~/Code/Valtech'], 5, (err, result) => {
if (err) throw err;
getCommitsFromRepos(result, 30, (err, result) => {
if (err) throw err;
console.log(result);
});
});
index.js
// Stolen from here:
// https://github.com/notwaldorf/tiny-care-terminal/blob/78e038069f01c36148d7d486d7775275d3df1df8/gitbot.js
const resolve = require('resolve-dir');
const subdirs = require('subdirs');
const isGit = require('is-git');
const gitlog = require('gitlog');
const path = require('path');
const async = require("async");
const git = require('git-utils');
try {
const gitUsername = require('git-user-name')();
} catch(err) {
console.error(`ERROR reading git-config.
Use e.g. 'git config --global user.name "Mona Lisa"'.
See 'man git config' for further information.
`);
return process.exit(0);
}
/**
* Go through all `repos` and look for subdirectories up to a given `depth`
* and look for repositories.
* Calls `callback` with array of repositories.
*/
function findGitRepos(repos, depth, callback) {
let allRepos = [];
async.each(repos, (repo, repoDone) => {
repo = resolve(repo);
subdirs(repo, depth, (err, dirs) => {
if (err) {
switch (err.code) {
case 'ENOENT':
return callback(`Could not open directory directory: ${err.path}n`, null);
case 'EACCES':
return; //ignore if no access
default:
return callback(`Error "${err.code}" doing "${err.syscall}" on directory: ${err.path}n`, null);
}
}
if (dirs) dirs.push(repo);
async.each(dirs, (dir, dirDone) => {
isGit(dir, (err, isGit) => {
if (err) {
return callback(err, null);
}
if (!dir.includes('.git') && isGit) {
allRepos.push(dir);
}
dirDone();
});
}, repoDone);
});
}, err => {
callback(err, allRepos.sort().reverse());
});
}
/**
* returns all commits of the last given `days`.
* Calls `callback` with line-seperated-strings of the formatted commits.
*/
function getCommitsFromRepos(repos, days, callback) {
let cmts = [];
async.each(repos, (repo, repoDone) => {
let localGitUsername = '';
try {
const gitUtilsRepo = git.open(repo);
localGitUsername = gitUtilsRepo.getConfigValue('user.name') || gitUsername;
} catch (err) {
localGitUsername = gitUsername;
}
try {
gitlog({
repo: repo,
all: true,
number: 100, //max commit count
since: `${days} days ago`,
fields: ['abbrevHash', 'subject', 'authorDate', 'authorName'],
author: localGitUsername
}, (err, logs) => {
// Error
if (err) {
callback(`Oh noes😱nThe repo ${repo} has failed:n${err}`, null);
}
// Find user commits
let commits = [];
logs.forEach(c => {
// filter simple merge commits
if (c.status && c.status.length)
commits.push(`${c.abbrevHash} - ${c.subject} (${c.authorDate}) <${c.authorName.replace('@end@n','')}>`);
});
// Add repo name and commits
if (commits.length >= 1) {
// Repo name
cmts.push(repo);
cmts.push(...commits);
}
repoDone();
});
} catch(err) {
callback(err, null);
}
}, err => {
callback(err, cmts.length > 0 ? cmts.join('n') : "Nothing yet. Start small!");
});
}
module.exports.findGitRepos = findGitRepos;
module.exports.getCommitsFromRepos = getCommitsFromRepos;
gitutils.js

Pointed vs. Point-Free JavaScript

const elementToCursorMoveAction = R.converge(
R.unapply(editorCursorMoveAction),
[selectSelectionStart, selectSelectionEnd]
);
point-free-action.js
const elementToCursorMoveAction = e =>
editorCursorMoveAction([selectSelectionStart(e), selectSelectionEnd(e)]);
pointed-action.js

What Order Does This Execute In?

setTimeout(() => {
console.log('inside timeout');
}, 0);
process.nextTick(() => {
console.log('inside nextTick');
});
const p = new Promise(function(resolve, reject) {
console.log('inside promise');
resolve();
})
.then(() => console.log('inside then'));
console.log('after promise');
promises.js

elm-types Strawman

import t from 'elm-types';
const AddTodo = t.Constructor('AddTodo', [t.String]);
const RemoveTodo = t.Constructor('AddTodo', [t.String]);
const Action = t.Union('Action', [AddTodo]);
const Todo = t.Record('Todo', {
name: t.String,
completed: t.Bool
});
const Model = t.Record('Model', {
todos: t.List('todos', Todo)
});
// Throws if function is not passed correct parameter types
const update = t.Function('update', [Model, Action, Model], (state, action) =>
// Throws if last object is not exaustive
t.case(action, Action, {
[AddTodo]: add => ({
...state,
todos: [...state.todos, Todo(add, false)]
}),
[RemoveTodo]: remove => ({
...state,
todos: state.todos.filter(todo => todo.name === remove)
})
});
);
const store = createStore(update, Model([]));
const App = ({ todos }) => (
<div>
<h1>Todo List</h1>
<ul>
{todos.map(todo => (
<li onClick={() => store.dispatch(RemoveTodo(todo.name))}>
{todo.name}
</li>
))}
</ul>
</div>
);
const AppProps = t.Record('AppProps', {
todos: t.List('todos', Todo)
});
App.propTypes = t.PropTypes(AppProps);
render(
<App {...store.getState()} />,
document.getElementById('app')
);
with-react-redux.js

flatten two ways

function flatten(source, acc = []) {
if (source.length === 0) return acc;
const [head, ...tail] = source;
return flatten(tail, [...acc, ...(Array.isArray(head) ? flatten(head) : [head])]);
}
console.log(flatten([1,2,[3,4,5,[6,7],8,[9]],10]));
recursive-flatten.js
import * as R from 'ramda';
const flatten = R.ifElse(
R.propSatisfies(R.equals(0), 'length'),
R.flip(R.identity),
R.converge((source, acc = []) => flatten(source, acc), [
R.tail,
R.useWith(R.flip(R.concat), [
R.pipe(R.head, R.ifElse(Array.isArray, head => flatten(head, []), R.of)),
R.identity
])
])
);
console.log(flatten([1,2,[3,4,5,[6,7],8,[9]],10], []));
point-free-flatten.js

Arrow function problems

function foo(ddb) {
return {
listTables: (params = {}, cb = idFunc) => {
const self = this
let currentList = params.currentList || []
return toPromise(ddb, ddb.listTables, omit(params, 'currentList'), cb)
.then(r => {
console.log('LISTTABLES result', r)
currentList = currentList.concat(r.TableNames || [])
if (!r.LastEvaluatedTableName || r.TableNames.length === 0) {
return { ...r, TableNames: currentList }
}
return self.listTables({ // <- Fails here
...params,
currentList,
ExclusiveStartTableName: r.LastEvaluatedTableName,
}, cb)
})
}
}
}
arrow-error.js
class MyClass {
myMethod = () => {
// ...code
}
}
class-methods.js