├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── CNAME ├── README.md ├── TODO.md ├── card ├── design │ ├── index.css │ └── index.js └── index.html ├── contact.html ├── cv ├── .gitignore ├── design │ ├── about │ │ └── chris.png │ ├── base.css │ ├── crypto │ │ ├── index.css │ │ └── index.js │ ├── index.css │ ├── index.js │ ├── open-source.css │ ├── profile.css │ └── section.css ├── index.html ├── secret.html └── source │ └── c6afd22545c477c9830ed96438a643317d6bbf38bb219df26ba837f3a10ecb99.cv ├── design ├── about │ ├── avatar │ │ ├── burp.mp3 │ │ ├── burp.ogg │ │ ├── burp.opus │ │ ├── burp.wav │ │ ├── cookiengineer.jpg │ │ ├── cookiengineer.png │ │ ├── index.css │ │ ├── index.js │ │ ├── melody.mp3 │ │ ├── melody.ogg │ │ ├── melody.opus │ │ ├── melody.wav │ │ ├── ouch.mp3 │ │ ├── ouch.ogg │ │ ├── ouch.opus │ │ ├── ouch.wav │ │ ├── vomit.mp3 │ │ ├── vomit.ogg │ │ ├── vomit.opus │ │ └── vomit.wav │ └── index.css ├── consent │ ├── booom.mp3 │ ├── cannon.png │ ├── cookie.png │ ├── cursor.cur │ ├── cursor.png │ ├── grass.png │ ├── index.css │ ├── index.js │ ├── lazer.mp3 │ └── music.mp3 ├── contact │ ├── captcha-human.svg │ ├── captcha-robot.svg │ ├── human.mp3 │ ├── human.ogg │ ├── human.opus │ ├── index.css │ ├── index.js │ ├── robot.mp3 │ ├── robot.ogg │ └── robot.opus ├── layout │ ├── base.css │ ├── cursor.cur │ ├── fontello.woff │ ├── fontello.woff2 │ ├── index.css │ ├── momentum.css │ ├── museo-sans-300.woff │ ├── museo-sans-300.woff2 │ ├── museo-sans-500.woff │ ├── museo-sans-500.woff2 │ ├── section.css │ ├── timeline.css │ ├── vera-mono.woff │ └── vera-mono.woff2 ├── magic │ ├── index.css │ └── index.js ├── menu │ ├── index.css │ └── index.js └── search │ ├── disabled.svg │ ├── hardware-legacy.svg │ ├── hardware-research-legacy.svg │ ├── hardware-research.svg │ ├── hardware-software-legacy.svg │ ├── hardware-software-research-legacy.svg │ ├── hardware-software-research.svg │ ├── hardware-software.svg │ ├── hardware.svg │ ├── index.css │ ├── index.js │ ├── legacy.svg │ ├── nothing.svg │ ├── research-legacy.svg │ ├── research.svg │ ├── software-legacy.svg │ ├── software-research-legacy.svg │ ├── software-research.svg │ └── software.svg ├── emergency.html ├── favicon.ico ├── index.html ├── projects.html ├── projects ├── adblock-proxy │ └── adblock-proxy.zip ├── ai-1-flappy-evolution │ ├── LICENSE_GPL3.txt │ ├── README.md │ ├── ai-1-flappy-evolution.zip │ ├── background.png │ ├── index.css │ ├── index.html │ ├── index.mjs │ ├── screenshot-small.png │ ├── screenshot.png │ └── source │ │ ├── Agent.mjs │ │ ├── Brain.mjs │ │ ├── Evolution.mjs │ │ ├── Game.mjs │ │ ├── Game.png │ │ ├── Goal.mjs │ │ ├── Goal.png │ │ ├── Plane.mjs │ │ ├── Plane.png │ │ ├── Simulation.mjs │ │ └── Twister.mjs ├── ai-2-pong │ ├── LICENSE_GPL3.txt │ ├── README.md │ ├── ai-2-pong.zip │ ├── background.png │ ├── index.css │ ├── index.html │ ├── index.mjs │ ├── screenshot-small.png │ ├── screenshot.png │ └── source │ │ ├── Agent.mjs │ │ ├── Ball.mjs │ │ ├── Brain.mjs │ │ ├── Game.mjs │ │ ├── Game.png │ │ ├── Paddle.blue.png │ │ ├── Paddle.mjs │ │ ├── Paddle.red.png │ │ └── Twister.mjs ├── ai-3-pong-evolution │ ├── LICENSE_GPL3.txt │ ├── README.md │ ├── ai-3-pong-evolution.zip │ ├── background.png │ ├── index.css │ ├── index.html │ ├── index.mjs │ ├── screenshot-small.png │ ├── screenshot.png │ └── source │ │ ├── Agent.mjs │ │ ├── Ball.mjs │ │ ├── Brain.mjs │ │ ├── Evolution.mjs │ │ ├── Game.mjs │ │ ├── Game.png │ │ ├── Paddle.blue.png │ │ ├── Paddle.mjs │ │ ├── Paddle.red.png │ │ ├── Simulation.mjs │ │ └── Twister.mjs ├── dns-proxy │ ├── screenshot-01-small.png │ └── screenshot-01.png ├── dnsquery │ ├── screenshot-01-small.png │ └── screenshot-01.png ├── gibook-editor │ ├── gibook-editor.zip │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ └── screenshot-02.png ├── git-cockpit │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ └── screenshot-02.png ├── git-work │ ├── git-work.zip │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ ├── screenshot-02.png │ ├── screenshot-03-small.png │ └── screenshot-03.png ├── github-scrumboard │ ├── github-scrumboard-0.0.4.crx │ ├── github-scrumboard.zip │ ├── github_scrumboard-0.0.4.xpi │ ├── screencast-01-small.png │ └── screencast-01.gif ├── gnome-shell-extension-outta-space │ └── gnome-shell-extension-outta-space.zip ├── jquery-desktop │ └── jquery-desktop.zip ├── lycheejs-breeder │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ ├── screenshot-02.png │ ├── screenshot-03-small.png │ └── screenshot-03.png ├── lycheejs-engine │ ├── lycheejs.zip │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ ├── screenshot-02.png │ ├── screenshot-03-small.png │ ├── screenshot-03.png │ ├── screenshot-04-small.png │ └── screenshot-04.png ├── lycheejs-fertilizer │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ └── screenshot-02.png ├── lycheejs-harvester │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ ├── screenshot-02.png │ ├── screenshot-03-small.png │ └── screenshot-03.png ├── me-want-cookies │ ├── me-want-cookies.zip │ ├── screenshot-01-small.png │ └── screenshot-01.png ├── pacman-backup │ ├── pacman-backup-1.0.0.zip │ └── pacman-backup-2.0.1.zip ├── patienteninfo-service │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ └── screenshot-02.png ├── polyfillr │ ├── polyfillr.zip │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ └── screenshot-02.png ├── research │ ├── research.zip │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ ├── screenshot-02.png │ ├── screenshot-03-small.png │ └── screenshot-03.png ├── skye-drone │ ├── skye-drone-01-small.jpg │ ├── skye-drone-01.jpg │ ├── skye-drone-02-small.jpg │ └── skye-drone-02.jpg ├── stealth │ ├── stealth-01-small.png │ ├── stealth-01.png │ ├── stealth-02-small.png │ ├── stealth-02.png │ ├── stealth-03-small.png │ ├── stealth-03.png │ ├── stealth-04-small.png │ └── stealth-04.png ├── stegit │ └── stegit.zip ├── switchine │ ├── switchine-01-small.png │ ├── switchine-01.png │ ├── switchine-02-small.png │ ├── switchine-02.png │ ├── switchine-03-small.png │ ├── switchine-03.png │ ├── switchine-04-small.png │ ├── switchine-04.png │ └── switchine.zip ├── webmail │ └── webmail.zip ├── webslide-me │ └── webslide-me.zip ├── zynga-jukebox │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ ├── screenshot-02.png │ ├── screenshot-03-small.png │ ├── screenshot-03.png │ └── zynga-jukebox.zip └── zynga-speedrun │ ├── css │ ├── library.css │ └── sidebar.css │ ├── index.html │ ├── js │ ├── external │ │ └── jquery-1.6.2.min.js │ ├── init.js │ ├── init_ui.js │ └── modules │ │ ├── FPS.js │ │ ├── benchmark.control.js │ │ ├── benchmark.hash.js │ │ ├── benchmark.js │ │ ├── benchmark.loops.js │ │ ├── benchmark.plugins.js │ │ ├── benchmark.position.js │ │ └── helpers.js │ ├── res │ └── debug.png │ ├── screenshot-01-small.png │ ├── screenshot-01.png │ ├── screenshot-02-small.png │ ├── screenshot-02.png │ ├── screenshot-03-small.png │ ├── screenshot-03.png │ └── zynga-speedrun.zip ├── talks.html ├── talks ├── 2012-ongamestart │ └── screenshot-01.png ├── 2014-jsconf-eu │ └── screenshot-01.png ├── 2014-karlsruhejs │ └── screenshot-01.png ├── 2016-frankfurtjs │ └── screenshot-01.png └── 2018-frankfurt-datascience │ └── screenshot-01.png ├── toolchain ├── actions │ ├── DecryptCV.go │ ├── EncryptCV.go │ ├── Render.go │ └── Serve.go ├── cmds │ ├── cv │ │ └── main.go │ ├── render │ │ └── main.go │ └── serve │ │ └── main.go ├── console │ ├── Clear.go │ ├── ClearLines.go │ ├── Disable.go │ ├── Enable.go │ ├── Error.go │ ├── Group.go │ ├── GroupEnd.go │ ├── GroupEndResult.go │ ├── Info.go │ ├── Inspect.go │ ├── Log.go │ ├── Message.go │ ├── Progress.go │ ├── Result.go │ ├── Warn.go │ ├── console.go │ └── features.go ├── cvs │ ├── Decrypt.go │ ├── DeriveFilename.go │ ├── DeriveKey.go │ ├── Encrypt.go │ └── cvs_test.go ├── go.mod ├── go.sum ├── routes │ ├── ModifyFile.go │ ├── RemoveFile.go │ ├── RenderArticle.go │ ├── RenderArticles.go │ ├── RenderFeed.go │ ├── RenderIndex.go │ ├── ServeArticle.go │ ├── ServeArticleIndex.go │ └── ServeFile.go ├── structs │ ├── Document.go │ ├── Element.go │ ├── Emojis.go │ ├── Feed.go │ ├── Index.go │ ├── countWords.go │ ├── generateId.go │ └── parseInlineElements.go ├── templates │ ├── Article.go │ ├── Article.tpl │ ├── Feed.go │ ├── Feed.tpl │ ├── Index.go │ ├── Index.tpl │ ├── RenderElement.go │ ├── RenderElements.go │ ├── RenderInteger.go │ └── RenderStrings.go └── utils │ ├── IsNumber.go │ ├── MIME.go │ ├── RespondWith.go │ ├── ToASCII.UTF8.json │ ├── ToASCII.go │ └── ToASCIIName.go └── weblog ├── articles ├── .eslintrc.json ├── android-privacy-guide.html ├── android-privacy-guide.md ├── android-privacy-guide │ ├── appwarden.jpg │ ├── osmand.jpg │ ├── permission-manager-x.jpg │ ├── rethinkdns.jpg │ └── superfreezz.jpg ├── archlinux-install-guide-grub.html ├── archlinux-install-guide-grub.md ├── archlinux-install-guide-uefi.html ├── archlinux-install-guide-uefi.md ├── dji-drone-reset-guide.html ├── dji-drone-reset-guide.md ├── dji-drone-reset-guide │ └── dji-spark-with-controller.jpg ├── email-with-postfix-and-dovecot.html ├── email-with-postfix-and-dovecot.md ├── gameboy-advance.html ├── gameboy-advance.md ├── gameboy-advance │ ├── gba-01-teardown.jpg │ ├── gba-02-cleanup.jpg │ ├── gba-03-displaymod.jpg │ └── gba-04-ezflash-omega.jpg ├── i3-migration-guide.html ├── i3-migration-guide.md ├── i3-migration-guide │ └── lxappearance.png ├── implementers-guide-to-socks.html ├── implementers-guide-to-socks.md ├── implementers-guide-to-socks │ ├── SOCKS.mjs │ ├── client-manual.mjs │ ├── client.mjs │ └── server.mjs ├── implementers-guide-to-websockets.html ├── implementers-guide-to-websockets.md ├── implementers-guide-to-websockets │ ├── WS.mjs │ ├── client.mjs │ └── server.mjs ├── intel-nuc-homeserver.html ├── intel-nuc-homeserver.md ├── intel-nuc-homeserver │ ├── fanless-intel-nuc-inside.jpg │ └── fanless-intel-nuc.jpg ├── linux-assembly-part-1-syscalls.html ├── linux-assembly-part-1-syscalls.md ├── linux-assembly-part-2-declaring-data.html ├── linux-assembly-part-2-declaring-data.md ├── linux-assembly-part-3-control-flow.html ├── linux-assembly-part-3-control-flow.md ├── linux-assembly-part-4-arithmetic-operations.html ├── linux-assembly-part-4-arithmetic-operations.md ├── linux-assembly │ ├── .gitignore │ ├── calculator.asm │ ├── hello-world.asm │ └── stack.asm ├── maintenance-of-clearnets.html ├── maintenance-of-clearnets.md ├── maintenance-of-clearnets │ ├── first-time.jpg │ ├── heist-attack.pdf │ ├── maximum-security-prison.jpg │ └── telephone-operator-lady.jpg ├── malware-insights-github-actions-script-injection.html ├── malware-insights-github-actions-script-injection.md ├── mx518-repair-guide.html ├── mx518-repair-guide.md ├── mx518-repair-guide │ ├── 01-mouse.jpg │ ├── 02-topshell.jpg │ ├── 03-mousewheel.jpg │ └── 04-components.jpg ├── nokia-800-tough.html ├── nokia-800-tough.md ├── pacman-backup.html ├── pacman-backup.md ├── pacman-backup │ └── screenshot.png ├── problems-with-web-browsers.html ├── problems-with-web-browsers.md ├── problems-with-web-browsers │ ├── firefox-cache-on-mobile-internet.png │ ├── firefox-network-connection-error.png │ ├── firefox-network-protocol-error.png │ ├── firefox-network-settings.png │ ├── stackoverflow-print-preview.png │ └── stealth-browser-settings.png ├── synaptics-touchpad-on-linux.html ├── synaptics-touchpad-on-linux.md ├── synaptics-touchpad-on-linux │ ├── 70-synaptics.conf │ └── lenovo-synaptics-touchpad.jpg ├── you-dont-need-lpm-tries.html ├── you-dont-need-lpm-tries.md ├── your-definition-of-privacy-is-wrong.html ├── your-definition-of-privacy-is-wrong.md └── your-definition-of-privacy-is-wrong │ ├── prefs.js │ └── umatrix-usage.png ├── design ├── editor │ ├── index.css │ ├── index.js │ ├── vera-mono.woff │ └── vera-mono.woff2 ├── index.css └── layout │ ├── article.css │ ├── article.js │ ├── highlight.css │ └── highlight.js ├── editor.html ├── feed.xml └── index.html /.eslintignore: -------------------------------------------------------------------------------- 1 | /design/weblog/highlight.js 2 | 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": false 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": 2018 10 | }, 11 | "globals": { 12 | "window": true 13 | }, 14 | "overrides": [{ 15 | "files": [ "*.mjs" ], 16 | "rules": {}, 17 | "parserOptions": { 18 | "sourceType": "module" 19 | } 20 | }, { 21 | "files": [ "bin/console.mjs" ], 22 | "rules": { "no-control-regex": "off" } 23 | }, { 24 | "files": [ "design/contact.js" ], 25 | "rules": { "no-control-regex": "off", "no-misleading-character-class": "off" } 26 | }], 27 | "rules": { 28 | "no-restricted-globals": [ 29 | "error", 30 | { "name": "console" }, 31 | { "name": "location" }, 32 | { "name": "URL" }, 33 | { "name": "URLSearchParams" } 34 | ], 35 | "arrow-parens": [ 36 | "error", 37 | "always" 38 | ], 39 | "indent": [ 40 | "error", 41 | "tab" 42 | ], 43 | "linebreak-style": [ 44 | "error", 45 | "unix" 46 | ], 47 | "no-unused-vars": [ 48 | "error" 49 | ], 50 | "quotes": [ 51 | "error", 52 | "single" 53 | ], 54 | "semi": [ 55 | "error", 56 | "always" 57 | ] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /cv/source/DECRYPTED.cv 2 | /toolchain/serve.bin 3 | 4 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | cookie.engineer 2 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | ## Projects 3 | 4 | Missing Tholian Projects: 5 | 6 | - [ ] Add `tholian-warps` (with Screenshots) 7 | 8 | Missing Artificial Engineering Projects: 9 | 10 | - [ ] Add `lychee.js Strainer` 11 | - [ ] Add `Research` (with Screenshots) 12 | - [ ] Add `ESA Satellite` (Galileo Networking/Firmware Infrastructure) 13 | - [ ] Add `ML for Dummies` 14 | - [ ] Add `node-sdl2` 15 | 16 | Missing Cookie Engineer Projects: 17 | 18 | - [ ] Add `agenda` screenshots 19 | - [ ] Add `gooey` WebASM framework 20 | - [ ] Add `gosleeper` malware infiltration framework 21 | - [ ] Add `goroot` privilege escalation framework 22 | - [ ] Add `git-evac` Git Repo Management Tool with screenshots 23 | - [ ] Add `evolution-of-code` 24 | - [ ] Add `infiltrator` 25 | - [ ] Add `lecture-tool` or rename it to `lecturer`? 26 | 27 | 28 | ## Weblog 29 | 30 | - [ ] MX518 Repair Guide 31 | 32 | - https://web.archive.org/web/20120423073234/http://ece425web.groups.et.byu.net/stable/labs/8086InstructionSet.html 33 | 34 | - https://www.bencode.net/blob/nasmcheatsheet.pdf 35 | - https://github.com/Cee/NASM-Tutorial 36 | - https://github.com/0xAX/asm/tree/master/content 37 | - https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf 38 | 39 | 40 | - [ ] Linux Assembly Part 3 - Control Flow 41 | - Stack Pointers 42 | - Function Calls 43 | 44 | - [ ] Linux Assembly Part 4 - Arithmetic Operations 45 | - [ ] Linux Assembly Part 5 - String Operations 46 | - [ ] Linux Assembly Part 6 - Inline Assembly (Call Assembly from C) 47 | - [ ] Linux Assembly Part 7 - X87 FPU 48 | 49 | - [ ] Go Assembly Part 1 50 | 51 | 52 | 53 | - [ ] Human Eyes Only - How to combat LLMs with the Enigma Webfont 54 | - [ ] The Ugly Internet - Crime, Propaganda and War 55 | - [ ] The Bad Internet - Greed, Persuasion and Seduction 56 | - [ ] The Toxic Internet - Trolls, Useful Idiots and Fragile Egos 57 | - [ ] The Good Internet - Research, Curiosity and Knowledge 58 | - [ ] One Year of Cyber Attacks - Who tried to hack me? 59 | - [ ] One Year of Cyber Attacks - Never use these passwords 60 | - [ ] One Year of Cyber Attacks - The most malicious networks 61 | - [ ] Golang Pitfalls (e.g. filtered maps of references needing twice the RAM) 62 | - [ ] PureGo for EDR Evasion 63 | - [ ] Go Embedding GZip files 64 | - [ ] Memory Debugging and Profiling in Go 65 | - [ ] Unmarshalling and Marshalling in Go 66 | - [ ] The WHOIS protocol and its quirks and pitfalls 67 | - [ ] Fingerprinting with CSS 68 | - [ ] Implementer's Guide to HTTP 69 | - [ ] Implementer's Guide to HTTP Streaming 70 | - [ ] Implementer's Guide to CSS 71 | 72 | -------------------------------------------------------------------------------- /card/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Cookie Engineer's Business Card 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 8.50 cm x 5.00 cm 20 | 21 | 22 |
23 |
24 | Cookie Engineer's Avatar 25 |

Cookie . Engineer

26 |

That's me. It's also my website.

27 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /cv/.gitignore: -------------------------------------------------------------------------------- 1 | /.temp.cv 2 | 3 | -------------------------------------------------------------------------------- /cv/design/about/chris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/cv/design/about/chris.png -------------------------------------------------------------------------------- /cv/design/crypto/index.css: -------------------------------------------------------------------------------- 1 | 2 | section#crypto { 3 | width: 100% !important; 4 | height: unset !important; 5 | border: unset; 6 | background: unset; 7 | box-shadow: unset; 8 | } 9 | 10 | section#crypto h1 { 11 | display: block; 12 | margin: 0px; 13 | padding: 0px; 14 | font-family: 'museo-sans-500'; 15 | font-size: 40px; 16 | line-height: 48px; 17 | font-weight: 500; 18 | text-align: center; 19 | } 20 | 21 | section#crypto article { 22 | display: block; 23 | position: static; 24 | top: unset; 25 | right: unset; 26 | bottom: unset; 27 | left: unset; 28 | width: 768px !important; 29 | height: auto !important; 30 | margin: 64px auto; 31 | padding: 16px; 32 | color: #ffffff; 33 | background: #252530; 34 | border: 0px solid transparent; 35 | border-radius: 16px; 36 | } 37 | 38 | section#crypto article input { 39 | display: block; 40 | box-sizing: border-box; 41 | width: calc(100% - 32px); 42 | margin: 16px auto 0px auto; 43 | font-family: 'museo-sans-300'; 44 | font-size: 16px; 45 | font-weight: normal; 46 | color: #ffffff; 47 | background: #404040; 48 | border: 1px solid #ffffff; 49 | border-radius: 4px; 50 | appearance: none; 51 | -moz-appearance: none; 52 | -ms-appearance: none; 53 | -webkit-appearance: none; 54 | user-select: none; 55 | -moz-user-select: none; 56 | -ms-user-select: none; 57 | outline: none; 58 | } 59 | 60 | section#crypto article ul { 61 | margin: 16px 0px 0px 0px; 62 | padding: 0px 16px 0px 16px; 63 | list-style: disc; 64 | text-align: left; 65 | } 66 | 67 | section#crypto article ul li { 68 | opacity: 0; 69 | transition: 200ms all ease-out; 70 | } 71 | 72 | section#crypto article ul li[data-show="true"] { 73 | opacity: 1; 74 | transition: 200ms all ease-out; 75 | } 76 | 77 | 78 | 79 | @media print { 80 | 81 | section#crypto { 82 | display: none !important; 83 | } 84 | 85 | } 86 | 87 | -------------------------------------------------------------------------------- /cv/design/index.css: -------------------------------------------------------------------------------- 1 | 2 | @import url("./base.css"); 3 | @import url("./section.css"); 4 | @import url("./profile.css"); 5 | @import url("./open-source.css"); 6 | 7 | -------------------------------------------------------------------------------- /cv/design/open-source.css: -------------------------------------------------------------------------------- 1 | 2 | section#open-source aside { 3 | top: 0px; 4 | padding: calc(64px + 16px) 0px 0px 0px; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /cv/design/profile.css: -------------------------------------------------------------------------------- 1 | 2 | section#profile figure#avatar { 3 | display: block; 4 | position: relative; 5 | width: 100%; 6 | margin-block-start: 0px; 7 | margin-block-end: 0px; 8 | margin-inline-start: 0px; 9 | margin-inline-end: 0px; 10 | margin: 0px auto 0px auto; 11 | } 12 | 13 | section#profile figure#avatar img { 14 | display: inline-block; 15 | position: relative; 16 | width: 128px; 17 | height: 128px; 18 | margin: 0px 0px 0px calc((200px / 2) - 64px - 8px); 19 | border-radius: 72px; 20 | border: 8px solid #252530; 21 | vertical-align: middle; 22 | cursor: pointer; 23 | user-select: none; 24 | -moz-user-select: none; 25 | -ms-user-select: none; 26 | z-index: 2; 27 | } 28 | 29 | section#profile figure#avatar figcaption { 30 | display: inline-block; 31 | position: absolute; 32 | width: auto%; 33 | margin: 0px; 34 | padding: 16px 0px 16px calc(128px + 16px + 64px); 35 | top: calc(64px / 2); 36 | right: 1em; 37 | bottom: auto; 38 | left: 0px; 39 | font-family: 'museo-sans-300'; 40 | font-size: 16px; 41 | line-height: 20px; 42 | vertical-align: middle; 43 | background: #252530; 44 | border-radius: 0px 64px 64px 0px; 45 | user-select: none; 46 | -moz-user-select: none; 47 | -ms-user-select: none; 48 | z-index: 1; 49 | } 50 | 51 | section#profile figure#avatar figcaption b { 52 | font-family: 'museo-sans-300'; 53 | font-size: 18px; 54 | } 55 | 56 | section#profile aside { 57 | top: calc((128px / 2) + 32px + 8px); 58 | padding: 64px 0px 0px 0px; 59 | } 60 | 61 | section#profile article { 62 | top: calc(128px - 8px); 63 | } 64 | 65 | -------------------------------------------------------------------------------- /cv/secret.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Cookie Engineer's CV - Cyber Engineer 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 30 |
31 | 32 |
33 |

Enter CV Password.

34 |
35 |

36 | Got a password from me? 37 | Enter it here to see all the secrets about me. 38 |

39 |

40 | This requires a Web Browser with support for the Web Crypto API. 41 | If you don't have a password and you still want to go ahead, feel free to take a look 42 | at the Source Code. 43 |

44 | 45 | 46 |
47 |
48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /cv/source/c6afd22545c477c9830ed96438a643317d6bbf38bb219df26ba837f3a10ecb99.cv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/cv/source/c6afd22545c477c9830ed96438a643317d6bbf38bb219df26ba837f3a10ecb99.cv -------------------------------------------------------------------------------- /design/about/avatar/burp.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/burp.mp3 -------------------------------------------------------------------------------- /design/about/avatar/burp.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/burp.ogg -------------------------------------------------------------------------------- /design/about/avatar/burp.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/burp.opus -------------------------------------------------------------------------------- /design/about/avatar/burp.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/burp.wav -------------------------------------------------------------------------------- /design/about/avatar/cookiengineer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/cookiengineer.jpg -------------------------------------------------------------------------------- /design/about/avatar/cookiengineer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/cookiengineer.png -------------------------------------------------------------------------------- /design/about/avatar/index.css: -------------------------------------------------------------------------------- 1 | 2 | section#about figure#avatar { 3 | display: block; 4 | position: relative; 5 | width: 640px; 6 | margin-block-start: 0px; 7 | margin-block-end: 0px; 8 | margin-inline-start: 0px; 9 | margin-inline-end: 0px; 10 | margin: 160px auto 0px auto; 11 | } 12 | 13 | section#about figure#avatar img { 14 | display: inline-block; 15 | position: relative; 16 | width: 256px; 17 | height: 256px; 18 | border-radius: 144px; 19 | border: 16px solid #252530; 20 | vertical-align: middle; 21 | user-select: none; 22 | -moz-user-select: none; 23 | -ms-user-select: none; 24 | z-index: 2; 25 | } 26 | 27 | section#about figure#avatar canvas { 28 | display: inline-block; 29 | position: absolute; 30 | width: 256px; 31 | height: 256px; 32 | top: 16px; 33 | right: auto; 34 | bottom: auto; 35 | left: 16px; 36 | user-select: none; 37 | -moz-user-select: none; 38 | -ms-user-select: none; 39 | z-index: 3; 40 | } 41 | 42 | section#about figure#avatar figcaption { 43 | display: inline-block; 44 | position: relative; 45 | width: 320px; 46 | margin: 0px 0px 0px -128px; 47 | padding: 24px 24px 24px 128px; 48 | font-family: 'museo-sans-300'; 49 | font-size: 20px; 50 | vertical-align: middle; 51 | background: #252530; 52 | border-radius: 0px 128px 128px 0px; 53 | user-select: none; 54 | -moz-user-select: none; 55 | -ms-user-select: none; 56 | z-index: 1; 57 | } 58 | 59 | section#about figure#avatar figcaption small { 60 | font-size: 16px; 61 | } 62 | 63 | section#about figure#avatar figcaption b { 64 | color: #0f99cb; 65 | font-weight: bold; 66 | } 67 | 68 | 69 | 70 | @media print { 71 | 72 | section#about figure#avatar { 73 | margin: 0px auto; 74 | } 75 | 76 | section#about figure#avatar canvas { 77 | display: none; 78 | } 79 | 80 | section#about figure#avatar figcaption { 81 | padding: 0px 0px 0px 148px; 82 | background: transparent; 83 | border-radius: 0px; 84 | } 85 | 86 | } 87 | 88 | 89 | 90 | /* 91 | * XXX: Something is glitching here, should've been 640px 92 | * but Chrome does not agree. Maybe it's the scrollbar!? 93 | */ 94 | 95 | @media screen and (max-width: 654px) { 96 | 97 | section#about figure#avatar { 98 | display: block; 99 | width: auto; 100 | } 101 | 102 | section#about figure#avatar img { 103 | display: block; 104 | margin: 0px auto; 105 | } 106 | 107 | section#about figure#avatar canvas { 108 | top: 16px; 109 | left: calc(50% - 128px); 110 | } 111 | 112 | section#about figure#avatar figcaption { 113 | display: block; 114 | width: auto; 115 | margin: 32px 0px; 116 | padding: 16px; 117 | border-radius: 4px; 118 | } 119 | 120 | } 121 | 122 | -------------------------------------------------------------------------------- /design/about/avatar/melody.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/melody.mp3 -------------------------------------------------------------------------------- /design/about/avatar/melody.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/melody.ogg -------------------------------------------------------------------------------- /design/about/avatar/melody.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/melody.opus -------------------------------------------------------------------------------- /design/about/avatar/melody.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/melody.wav -------------------------------------------------------------------------------- /design/about/avatar/ouch.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/ouch.mp3 -------------------------------------------------------------------------------- /design/about/avatar/ouch.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/ouch.ogg -------------------------------------------------------------------------------- /design/about/avatar/ouch.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/ouch.opus -------------------------------------------------------------------------------- /design/about/avatar/ouch.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/ouch.wav -------------------------------------------------------------------------------- /design/about/avatar/vomit.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/vomit.mp3 -------------------------------------------------------------------------------- /design/about/avatar/vomit.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/vomit.ogg -------------------------------------------------------------------------------- /design/about/avatar/vomit.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/vomit.opus -------------------------------------------------------------------------------- /design/about/avatar/vomit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/about/avatar/vomit.wav -------------------------------------------------------------------------------- /design/consent/booom.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/consent/booom.mp3 -------------------------------------------------------------------------------- /design/consent/cannon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/consent/cannon.png -------------------------------------------------------------------------------- /design/consent/cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/consent/cookie.png -------------------------------------------------------------------------------- /design/consent/cursor.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/consent/cursor.cur -------------------------------------------------------------------------------- /design/consent/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/consent/cursor.png -------------------------------------------------------------------------------- /design/consent/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/consent/grass.png -------------------------------------------------------------------------------- /design/consent/index.css: -------------------------------------------------------------------------------- 1 | 2 | #consent { 3 | display: block; 4 | position: fixed; 5 | width: 448px; 6 | top: auto; 7 | right: 0px; 8 | bottom: 0px; 9 | left: 0px; 10 | margin: 0px auto; 11 | padding: 8px; 12 | border: 1px solid #000000; 13 | color: #000000; 14 | background: #ffffff; 15 | border-radius: 8px 8px 0px 0px; 16 | box-sizing: border-box; 17 | transition: 250ms all ease-out; 18 | opacity: 1; 19 | z-index: 99; 20 | } 21 | 22 | #consent h3 { 23 | display: block; 24 | margin: 0px; 25 | padding: 0px; 26 | font-family: 'museo-sans-500'; 27 | font-size: 24px; 28 | line-height: 32px; 29 | font-weight: 500; 30 | text-align: center; 31 | } 32 | 33 | #consent p { 34 | font-family: 'museo-sans-300'; 35 | text-align: justify; 36 | margin: 8px 0px 16px 0px; 37 | padding: 0px; 38 | } 39 | 40 | #consent div { 41 | text-align: center; 42 | } 43 | 44 | #consent div button { 45 | margin: 0px 16px; 46 | } 47 | 48 | body.game #consent { 49 | opacity: 0; 50 | } 51 | 52 | body.game #consent h3, 53 | body.game #consent p, 54 | body.game #consent div, 55 | body.game #consent div button { 56 | display: none; 57 | } 58 | 59 | body.game { 60 | width: 100%; 61 | height: 100%; 62 | overflow: hidden; 63 | background: #000000; 64 | transition: all 250ms ease-out; 65 | cursor: url('./cursor.cur') 16 16, auto; 66 | } 67 | 68 | body.game header { 69 | display: none; 70 | } 71 | 72 | body.game section#about > h1 { 73 | display: none; 74 | } 75 | 76 | body.game section#about > article { 77 | display: none; 78 | } 79 | 80 | body.game section#about div#about-socialize { 81 | display: none; 82 | } 83 | 84 | body.game section#about figure#avatar figcaption { 85 | display: none; 86 | } 87 | 88 | body.game section#skills, 89 | body.game section#prototypes, 90 | body.game section#search, 91 | body.game section#open-source, 92 | body.game section#talks, 93 | body.game section#contact, 94 | body.game footer { 95 | display: none; 96 | } 97 | 98 | 99 | 100 | @media (max-width: 512px) { 101 | 102 | #consent { 103 | width: auto; 104 | } 105 | 106 | } 107 | 108 | -------------------------------------------------------------------------------- /design/consent/lazer.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/consent/lazer.mp3 -------------------------------------------------------------------------------- /design/consent/music.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/consent/music.mp3 -------------------------------------------------------------------------------- /design/contact/captcha-robot.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /design/contact/human.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/contact/human.mp3 -------------------------------------------------------------------------------- /design/contact/human.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/contact/human.ogg -------------------------------------------------------------------------------- /design/contact/human.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/contact/human.opus -------------------------------------------------------------------------------- /design/contact/robot.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/contact/robot.mp3 -------------------------------------------------------------------------------- /design/contact/robot.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/contact/robot.ogg -------------------------------------------------------------------------------- /design/contact/robot.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/contact/robot.opus -------------------------------------------------------------------------------- /design/layout/cursor.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/cursor.cur -------------------------------------------------------------------------------- /design/layout/fontello.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/fontello.woff -------------------------------------------------------------------------------- /design/layout/fontello.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/fontello.woff2 -------------------------------------------------------------------------------- /design/layout/index.css: -------------------------------------------------------------------------------- 1 | 2 | @import url("./base.css"); 3 | @import url("./section.css"); 4 | @import url("./momentum.css"); 5 | @import url("./timeline.css"); 6 | 7 | -------------------------------------------------------------------------------- /design/layout/museo-sans-300.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/museo-sans-300.woff -------------------------------------------------------------------------------- /design/layout/museo-sans-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/museo-sans-300.woff2 -------------------------------------------------------------------------------- /design/layout/museo-sans-500.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/museo-sans-500.woff -------------------------------------------------------------------------------- /design/layout/museo-sans-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/museo-sans-500.woff2 -------------------------------------------------------------------------------- /design/layout/vera-mono.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/vera-mono.woff -------------------------------------------------------------------------------- /design/layout/vera-mono.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/design/layout/vera-mono.woff2 -------------------------------------------------------------------------------- /design/magic/index.css: -------------------------------------------------------------------------------- 1 | 2 | * > ._magic_, 3 | * > ._magic_ > * { 4 | display: inline-block !important; 5 | position: fixed !important; 6 | top: 0px !important; 7 | left: 0px !important; 8 | width: 1px !important; 9 | height: 1px !important; 10 | font-color: transparent !important; 11 | font-size: 0.1px !important; 12 | line-height: 0.1px !important; 13 | vertical-align: top !important; 14 | speak: none !important; 15 | overflow: hidden !important; 16 | z-index: -1 !important; 17 | } 18 | 19 | 20 | 21 | @media print { 22 | 23 | * > ._magic_, 24 | * > ._magic_ > * { 25 | display: none !important; 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /design/search/disabled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /design/search/hardware-legacy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 16 | 18 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /design/search/hardware-research-legacy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 15 | 17 | 19 | 20 | 22 | 24 | 26 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /design/search/hardware-research.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 16 | 18 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /design/search/hardware-software.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 9 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /design/search/hardware.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /design/search/legacy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 13 | 15 | 17 | 18 | 20 | 24 | 25 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /design/search/nothing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /design/search/research.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 12 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /design/search/software.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/favicon.ico -------------------------------------------------------------------------------- /projects/adblock-proxy/adblock-proxy.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/adblock-proxy/adblock-proxy.zip -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Flappy Evolution 3 | 4 | This Game was a part of the AI Crash Course Workshop I held 5 | on various events. It's an in-Browser Implementation of a 6 | simple Evolutionary AI that evolves a simple Feed-Forward 7 | Neural Network strictly by using randomization and genetic 8 | cross-breeding, without any reinforcement Learning. 9 | 10 | 11 | ## License 12 | 13 | This project is licensed under [GNU GPL 3](./LICENSE_GPL3.txt) 14 | and is `(c) 2017-2021 Cookie Engineer`. 15 | 16 | -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/ai-1-flappy-evolution.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-1-flappy-evolution/ai-1-flappy-evolution.zip -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-1-flappy-evolution/background.png -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/index.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | margin: 0px; 4 | padding: 0px; 5 | background: #404552; 6 | } 7 | 8 | body * { 9 | -webkit-user-select: none; 10 | -moz-user-select: none; 11 | -ms-user-select: none; 12 | user-select: none; 13 | } 14 | 15 | aside { 16 | display: block; 17 | position: fixed; 18 | top: 0px; 19 | right: 0px; 20 | bottom: auto; 21 | left: 0px; 22 | margin: 0px; 23 | padding: 16px; 24 | text-align: center; 25 | border-left: 1px solid #2a2c36; 26 | background: #333742; 27 | z-index: 2; 28 | } 29 | 30 | aside h3 { 31 | display: block; 32 | margin: 0px auto 16px auto; 33 | padding: 0px; 34 | color: #ffffff; 35 | font-size: 32px; 36 | font-family: 'DejaVu Sans'; 37 | text-align: center; 38 | line-height: 32px; 39 | vertical-align: middle; 40 | } 41 | 42 | aside a { 43 | display: block; 44 | position: absolute; 45 | top: 16px; 46 | right: 16px; 47 | color: #ffffff; 48 | font-family: 'DejaVu Sans'; 49 | font-size: 16px; 50 | text-decoration: none; 51 | } 52 | 53 | aside a:hover, 54 | aside a:focus { 55 | color: #4dadd4; 56 | transition: all 250ms ease-out; 57 | } 58 | 59 | aside button { 60 | display: inline-block; 61 | vertical-align: top; 62 | font-size: 16px; 63 | line-height: 24px; 64 | color: #ffffff; 65 | background: #3e4351; 66 | border: 1px solid #2a2c36; 67 | border-radius: 4px; 68 | transition: all 250ms ease-out; 69 | vertical-align: middle; 70 | outline: none; 71 | cursor: pointer; 72 | } 73 | 74 | aside button:hover, 75 | aside button:focus { 76 | outline: none; 77 | background: #677085; 78 | transition: all 250ms ease-out; 79 | } 80 | 81 | aside button:active { 82 | outline: none; 83 | background: #4dadd4; 84 | transition: all 0ms ease-out; 85 | } 86 | 87 | aside button[disabled], 88 | aside button[disabled]:hover 89 | aside button[disabled]:focus, 90 | aside button[disabled]:active { 91 | color: #677085; 92 | background: #3e4351; 93 | } 94 | 95 | aside span { 96 | display: inline-block; 97 | width: 32px; 98 | } 99 | 100 | aside i { 101 | display: inline-block; 102 | margin: 0px 0px 0px 32px; 103 | color: #ffffff; 104 | font-family: 'DejaVu Sans'; 105 | font-weight: normal; 106 | font-style: normal; 107 | vertical-align: middle; 108 | } 109 | 110 | canvas { 111 | position: absolute; 112 | top: 50%; 113 | top: calc(50% + 64px); 114 | right: auto; 115 | bottom: auto; 116 | left: 50%; 117 | transform: translate(-50%, -50%); 118 | border: 1px solid #2a2c36; 119 | -webkit-user-select: none; 120 | -moz-user-select: none; 121 | -ms-user-select: none; 122 | user-select: none; 123 | background: url('./background.png') center center; 124 | z-index: 1; 125 | } 126 | 127 | -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Flappy Plane Evolution 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/index.mjs: -------------------------------------------------------------------------------- 1 | 2 | import { Simulation } from './source/Simulation.mjs'; 3 | 4 | 5 | 6 | const SIMULATION = window.SIMULATION = new Simulation(); 7 | const control = function(/* e */) { 8 | 9 | let player = SIMULATION.game.planes[0] || null; 10 | if (player !== null) { 11 | player.jump(); 12 | } 13 | 14 | }; 15 | 16 | 17 | let fps_buttons = Array.from(document.querySelectorAll('button.set-fps')); 18 | if (fps_buttons.length > 0) { 19 | 20 | fps_buttons.forEach((button) => { 21 | 22 | button.onclick = () => { 23 | 24 | let fps = parseInt(button.getAttribute('data-fps'), 10); 25 | 26 | if (Number.isNaN(fps) === false && fps > 0) { 27 | SIMULATION.setFPS(fps); 28 | } 29 | 30 | }; 31 | 32 | }); 33 | 34 | } 35 | 36 | 37 | let manual_button = document.querySelector('button#game-manual'); 38 | if (manual_button !== null) { 39 | 40 | manual_button.onclick = () => { 41 | 42 | manual_button.setAttribute('disabled', true); 43 | fps_buttons.forEach((button) => button.setAttribute('disabled', true)); 44 | 45 | SIMULATION.stop(); 46 | 47 | setTimeout(() => { 48 | 49 | SIMULATION.game.population = []; 50 | SIMULATION.game.setFPS(60); 51 | SIMULATION.game.start(); 52 | 53 | SIMULATION.update(); 54 | SIMULATION.render(); 55 | 56 | document.querySelector('canvas').addEventListener('click', control); 57 | auto_button.removeAttribute('disabled'); 58 | 59 | }, 500); 60 | 61 | }; 62 | 63 | manual_button.removeAttribute('disabled'); 64 | 65 | } 66 | 67 | 68 | let auto_button = document.querySelector('button#game-auto'); 69 | if (auto_button !== null) { 70 | 71 | auto_button.onclick = () => { 72 | 73 | auto_button.setAttribute('disabled', true); 74 | fps_buttons.forEach((button) => button.removeAttribute('disabled')); 75 | 76 | SIMULATION.stop(); 77 | 78 | setTimeout(() => { 79 | 80 | SIMULATION.setFPS(60); 81 | 82 | SIMULATION.start(); 83 | SIMULATION.update(); 84 | SIMULATION.render(); 85 | 86 | document.querySelector('canvas').removeEventListener('click', control); 87 | manual_button.removeAttribute('disabled'); 88 | 89 | }, 500); 90 | 91 | }; 92 | 93 | auto_button.removeAttribute('disabled'); 94 | 95 | } 96 | 97 | -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/screenshot-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-1-flappy-evolution/screenshot-small.png -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-1-flappy-evolution/screenshot.png -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/source/Agent.mjs: -------------------------------------------------------------------------------- 1 | 2 | import { Brain } from './Brain.mjs'; 3 | 4 | 5 | 6 | const BRAIN_REFERENCE = { 7 | inputs: [ 8 | 0.5, // plane position 9 | 0.6 // goal position 10 | ], 11 | outputs: [ 12 | 1 // jump action 13 | ] 14 | }; 15 | 16 | 17 | 18 | const Agent = function() { 19 | 20 | this.brain = new Brain(); 21 | this.fitness = 0; 22 | 23 | 24 | // XXX: Brain needs a reference dataset 25 | this.brain.initialize( 26 | BRAIN_REFERENCE.inputs, 27 | BRAIN_REFERENCE.outputs 28 | ); 29 | 30 | }; 31 | 32 | 33 | Agent.prototype = { 34 | 35 | compute: function(inputs) { 36 | return this.brain.compute(inputs); 37 | }, 38 | 39 | clone: function() { 40 | 41 | let clone = new Agent(); 42 | 43 | // This will copy/paste the exact same Brain 44 | // onto our clone. We need this method for 45 | // having non-linked Survivors as Survivors 46 | // are Elite and can be bred into other Babies 47 | // 48 | // This avoids basically that one Agent can 49 | // by coincidence be used for several Entities 50 | 51 | clone.fitness = this.fitness; 52 | clone.brain.layers = JSON.parse(JSON.stringify(this.brain.layers)); 53 | 54 | 55 | return clone; 56 | 57 | }, 58 | 59 | crossover: function(agent) { 60 | 61 | let babies = [ new Agent(), new Agent() ]; 62 | let brain0 = []; 63 | let brain1 = []; 64 | let weights_mum = this.brain.serialize(); 65 | let weights_dad = agent.brain.serialize(); 66 | let dnasplit = (Math.random() * weights_mum.length) | 0; 67 | 68 | 69 | for (let w = 0, wl = weights_mum.length; w < wl; w++) { 70 | 71 | // Cross-Breeding 72 | // 73 | // - DNA is "only" the weights of the brain 74 | // - first part of DNA is mum 75 | // - second part of DNA is dad 76 | 77 | if (w < dnasplit) { 78 | brain0[w] = weights_mum[w]; 79 | brain1[w] = weights_dad[w]; 80 | } else { 81 | brain0[w] = weights_dad[w]; 82 | brain1[w] = weights_mum[w]; 83 | } 84 | 85 | 86 | // Mutations 87 | // 88 | // - 10% Mutation Rate 89 | // - 25% Mutation Range 90 | // - Math.random() is only positive 91 | // - Math.random() * 2 - 1 can lead to negative value 92 | 93 | if (Math.random() <= 0.10) { 94 | brain0[w] += (Math.random() * 0.25 * 2) - 0.25; 95 | brain1[w] += (Math.random() * 0.25 * 2) - 0.25; 96 | } 97 | 98 | } 99 | 100 | 101 | // Baby Brains 102 | // - brain weights were generated by DNA above 103 | 104 | babies[0].brain.deserialize(brain0); 105 | babies[1].brain.deserialize(brain1); 106 | 107 | 108 | return babies; 109 | 110 | } 111 | 112 | }; 113 | 114 | 115 | 116 | export { Agent }; 117 | 118 | -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/source/Game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-1-flappy-evolution/source/Game.png -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/source/Goal.mjs: -------------------------------------------------------------------------------- 1 | 2 | let IMAGE = null; 3 | 4 | (function() { 5 | 6 | let img = new Image(); 7 | 8 | img.onload = function() { 9 | IMAGE = this; 10 | }; 11 | 12 | img.src = './source/Goal.png'; 13 | 14 | })(); 15 | 16 | 17 | 18 | const Goal = function(data) { 19 | 20 | this.x = 0; 21 | this.y = 0; 22 | 23 | this.alive = true; 24 | this.width = 40; 25 | this.height = 256; 26 | this.velocity = 3; 27 | 28 | if (data instanceof Object) { 29 | Object.assign(this, data); 30 | } 31 | 32 | }; 33 | 34 | 35 | Goal.prototype = { 36 | 37 | update: function(/* game */) { 38 | 39 | this.x -= this.velocity; 40 | 41 | 42 | let x = this.x; 43 | let width = this.width; 44 | 45 | 46 | if (x + width < 0) { 47 | this.alive = false; 48 | } 49 | 50 | }, 51 | 52 | render: function(context) { 53 | 54 | if (IMAGE !== null) { 55 | 56 | context.drawImage( 57 | IMAGE, 58 | this.x - 1 / 2 * this.width, 59 | this.y - 1 / 2 * this.height, 60 | this.width, 61 | this.height 62 | ); 63 | 64 | /* 65 | context.strokeStyle = '#4dadd4'; 66 | context.strokeRect( 67 | this.x - 1/2 * this.width, 68 | this.y - 1/2 * this.height, 69 | this.width, 70 | this.height 71 | ); 72 | */ 73 | 74 | } 75 | 76 | } 77 | 78 | }; 79 | 80 | 81 | 82 | export { Goal }; 83 | 84 | -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/source/Goal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-1-flappy-evolution/source/Goal.png -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/source/Plane.mjs: -------------------------------------------------------------------------------- 1 | 2 | let IMAGE = null; 3 | 4 | (function() { 5 | 6 | let img = new Image(); 7 | 8 | img.onload = function() { 9 | IMAGE = this; 10 | }; 11 | 12 | img.src = './source/Plane.png'; 13 | 14 | })(); 15 | 16 | 17 | 18 | const Plane = function() { 19 | 20 | this.x = 64; 21 | this.y = 254; 22 | this.width = 40; 23 | this.height = 32; 24 | 25 | this.alive = true; 26 | this.gravity = 0; 27 | this.velocity = 0.30; 28 | 29 | }; 30 | 31 | Plane.prototype = { 32 | 33 | jump: function() { 34 | this.gravity = -6; 35 | }, 36 | 37 | render: function(context) { 38 | 39 | let width = this.width; 40 | let height = this.height; 41 | 42 | 43 | context.save(); 44 | 45 | context.translate( 46 | this.x, 47 | this.y 48 | ); 49 | 50 | context.rotate(Math.PI / 2 * this.gravity / 20); 51 | 52 | if (IMAGE !== null) { 53 | 54 | context.drawImage( 55 | IMAGE, 56 | -1 / 2 * width, 57 | -1 / 2 * height, 58 | width, 59 | height 60 | ); 61 | 62 | } 63 | 64 | context.restore(); 65 | 66 | }, 67 | 68 | update: function(game) { 69 | 70 | // Gravity is in Y direction 71 | // Plane never moves in X direction 72 | // (Game moves Goals, not Planes) 73 | this.gravity += this.velocity; 74 | this.y += this.gravity; 75 | 76 | 77 | let x = this.x; 78 | let y = this.y; 79 | let hw = this.width / 2; 80 | let hh = this.height / 2; 81 | 82 | 83 | // Plane moves outside Game Field 84 | // - dies if flapped too high 85 | // - dies if gravity caused crash 86 | if (y >= game.height || y <= 0) { 87 | this.alive = false; 88 | } 89 | 90 | 91 | if (this.alive === true) { 92 | 93 | // AABB collisions for Plane with each Goal 94 | for (let g = 0, gl = game.goals.length; g < gl; g++) { 95 | 96 | let goal = game.goals[g]; 97 | let ghw = goal.width / 2; 98 | let ghh = goal.height / 2; 99 | 100 | // XXX: Boxes are 40px each 101 | // but game will be too hard to solve 102 | // let ghh = (goal.height - 80) / 2; 103 | 104 | let min_x = goal.x - ghw; 105 | let max_x = goal.x + ghw; 106 | let min_y = goal.y - ghh; 107 | let max_y = goal.y + ghh; 108 | 109 | if (x + hw > min_x && x - hw < max_x) { 110 | 111 | if (y - hh > min_y && y + hh < max_y) { 112 | // this.alive = true; 113 | } else { 114 | this.alive = false; 115 | break; 116 | } 117 | 118 | } 119 | 120 | } 121 | 122 | } 123 | 124 | } 125 | 126 | }; 127 | 128 | 129 | export { Plane }; 130 | 131 | -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/source/Plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-1-flappy-evolution/source/Plane.png -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/source/Simulation.mjs: -------------------------------------------------------------------------------- 1 | 2 | import { Game } from './Game.mjs'; 3 | import { Evolution } from './Evolution.mjs'; 4 | 5 | 6 | 7 | const Simulation = function() { 8 | 9 | this.evolution = new Evolution({ population: 64 }); 10 | this.fps = 60; 11 | this.game = new Game(); 12 | 13 | }; 14 | 15 | 16 | Simulation.prototype = { 17 | 18 | start: function() { 19 | 20 | let population = this.evolution.cycle(); 21 | 22 | this.game.population = population; 23 | this.game.start(); 24 | 25 | }, 26 | 27 | restart: function() { 28 | 29 | let population = this.evolution.cycle(); 30 | 31 | this.game.population = population; 32 | this.game.restart(); 33 | 34 | this.update(); 35 | this.render(); 36 | 37 | }, 38 | 39 | stop: function() { 40 | 41 | this.game.stop(); 42 | 43 | }, 44 | 45 | update: function() { 46 | 47 | if (this.game._has_ended === false) { 48 | this.game.update(); 49 | } 50 | 51 | if (this.game._has_ended === false) { 52 | setTimeout(() => this.update(), 1000 / this.fps); 53 | } else { 54 | setTimeout(() => this.restart(), 16); 55 | } 56 | 57 | }, 58 | 59 | render: function() { 60 | 61 | if (this.game._has_ended === false) { 62 | this.game.render(); 63 | } 64 | 65 | if (this.game._has_ended === false) { 66 | requestAnimationFrame(() => this.render()); 67 | } 68 | 69 | }, 70 | 71 | 72 | 73 | /* 74 | * CUSTOM API 75 | */ 76 | 77 | setFPS: function(fps) { 78 | 79 | fps = typeof fps === 'number' ? fps : 60; 80 | 81 | 82 | if (this.fps !== fps) { 83 | 84 | this.fps = fps; 85 | this.game.setFPS(fps); 86 | 87 | return true; 88 | 89 | } 90 | 91 | 92 | return false; 93 | 94 | } 95 | 96 | }; 97 | 98 | 99 | 100 | export { Simulation }; 101 | 102 | -------------------------------------------------------------------------------- /projects/ai-1-flappy-evolution/source/Twister.mjs: -------------------------------------------------------------------------------- 1 | 2 | const UPPER_MASK = 0x80000000; 3 | const LOWER_MASK = 0x7fffffff; 4 | const XOR_MATRIX = new Array(0x0, 0x9908b0df); 5 | 6 | const initialize = function(seed) { 7 | 8 | let index = 1; 9 | let N = this.N; 10 | let twister = this.twister; 11 | 12 | 13 | twister[0] = seed >>> 0; 14 | 15 | 16 | while (index < N) { 17 | 18 | let value = twister[index - 1] ^ (twister[index - 1] >>> 30); 19 | 20 | twister[index] = (((((value & 0xffff0000) >>> 16) * 1812433253) << 16) + (value & 0x0000ffff) * 1812433253) + index; 21 | twister[index] >>>= 0; 22 | 23 | index++; 24 | 25 | } 26 | 27 | this.index = index; 28 | 29 | }; 30 | 31 | const random_int32 = function() { 32 | 33 | let index = this.index; 34 | let twister = this.twister; 35 | let value = 0; 36 | let M = this.M; 37 | let N = this.N; 38 | 39 | 40 | if (index >= N) { 41 | 42 | let i = 0; 43 | 44 | if (index === N + 1) { 45 | initialize.call(this, 5489); 46 | } 47 | 48 | 49 | while (i < N - M) { 50 | 51 | value = (twister[i] & UPPER_MASK) | (twister[i + 1] & LOWER_MASK); 52 | twister[i] = twister[i + M] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 53 | 54 | i++; 55 | 56 | } 57 | 58 | while (i < N - 1) { 59 | 60 | value = (twister[i] & UPPER_MASK) | (twister[i + 1] & LOWER_MASK); 61 | twister[i] = twister[i + (M - N)] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 62 | 63 | i++; 64 | 65 | } 66 | 67 | 68 | value = (twister[N - 1] & UPPER_MASK) | (twister[0] & LOWER_MASK); 69 | twister[N - 1] = twister[M - 1] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 70 | 71 | this.index = 0; 72 | 73 | } 74 | 75 | 76 | value = twister[this.index++]; 77 | 78 | value ^= (value >>> 11); 79 | value ^= (value << 7) & 0x9d2c5680; 80 | value ^= (value << 15) & 0xefc60000; 81 | value ^= (value >>> 18); 82 | 83 | 84 | return value >>> 0; 85 | 86 | }; 87 | 88 | 89 | 90 | const Twister = function(seed) { 91 | 92 | seed = typeof seed === 'number' ? (seed | 0) : ((Math.random() * Number.MAX_SAFE_INTEGER) | 0); 93 | 94 | 95 | this.N = 624; 96 | this.M = 397; 97 | 98 | this.twister = new Array(this.N); 99 | this.index = this.N + 1; 100 | 101 | this.__seed = seed; 102 | 103 | 104 | initialize.call(this, seed); 105 | 106 | seed = null; 107 | 108 | }; 109 | 110 | 111 | Twister.prototype = { 112 | 113 | random: function() { 114 | 115 | return random_int32.call(this) * (1.0 / 4294967296.0); 116 | 117 | } 118 | 119 | }; 120 | 121 | 122 | 123 | export { Twister }; 124 | -------------------------------------------------------------------------------- /projects/ai-2-pong/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Reinforcement Pong AI 3 | 4 | This Game was a part of the AI Crash Course Workshop I held 5 | on various events. It's an in-Browser Implementation of a 6 | simple Reinforcement AI that also can be manually played 7 | against. 8 | 9 | 10 | ## License 11 | 12 | This project is licensed under [GNU GPL 3](./LICENSE_GPL3.txt) 13 | and is `(c) 2017-2021 Cookie Engineer`. 14 | 15 | -------------------------------------------------------------------------------- /projects/ai-2-pong/ai-2-pong.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-2-pong/ai-2-pong.zip -------------------------------------------------------------------------------- /projects/ai-2-pong/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-2-pong/background.png -------------------------------------------------------------------------------- /projects/ai-2-pong/index.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | margin: 0px; 4 | padding: 0px; 5 | background: #404552; 6 | } 7 | 8 | body * { 9 | -webkit-user-select: none; 10 | -moz-user-select: none; 11 | -ms-user-select: none; 12 | user-select: none; 13 | } 14 | 15 | aside { 16 | display: block; 17 | position: fixed; 18 | top: 0px; 19 | right: 0px; 20 | bottom: auto; 21 | left: 0px; 22 | margin: 0px; 23 | padding: 16px; 24 | text-align: center; 25 | border-left: 1px solid #2a2c36; 26 | background: #333742; 27 | z-index: 2; 28 | } 29 | 30 | aside h3 { 31 | display: block; 32 | margin: 0px auto 16px auto; 33 | padding: 0px; 34 | color: #ffffff; 35 | font-size: 32px; 36 | font-family: 'DejaVu Sans'; 37 | text-align: center; 38 | line-height: 32px; 39 | vertical-align: middle; 40 | } 41 | 42 | aside a { 43 | display: block; 44 | position: absolute; 45 | top: 16px; 46 | right: 16px; 47 | color: #ffffff; 48 | font-family: 'DejaVu Sans'; 49 | font-size: 16px; 50 | text-decoration: none; 51 | } 52 | 53 | aside a:hover, 54 | aside a:focus { 55 | color: #4dadd4; 56 | transition: all 250ms ease-out; 57 | } 58 | 59 | aside button { 60 | display: inline-block; 61 | vertical-align: top; 62 | font-size: 16px; 63 | line-height: 24px; 64 | color: #ffffff; 65 | background: #3e4351; 66 | border: 1px solid #2a2c36; 67 | border-radius: 4px; 68 | transition: all 250ms ease-out; 69 | vertical-align: middle; 70 | outline: none; 71 | cursor: pointer; 72 | } 73 | 74 | aside button:hover, 75 | aside button:focus { 76 | outline: none; 77 | background: #677085; 78 | transition: all 250ms ease-out; 79 | } 80 | 81 | aside button:active { 82 | outline: none; 83 | background: #4dadd4; 84 | transition: all 0ms ease-out; 85 | } 86 | 87 | aside button[disabled], 88 | aside button[disabled]:hover 89 | aside button[disabled]:focus, 90 | aside button[disabled]:active { 91 | color: #677085; 92 | background: #3e4351; 93 | } 94 | 95 | aside span { 96 | display: inline-block; 97 | width: 32px; 98 | } 99 | 100 | aside i { 101 | display: inline-block; 102 | margin: 0px 0px 0px 32px; 103 | color: #ffffff; 104 | font-family: 'DejaVu Sans'; 105 | font-weight: normal; 106 | font-style: normal; 107 | vertical-align: middle; 108 | } 109 | 110 | canvas { 111 | position: absolute; 112 | top: 50%; 113 | top: calc(50% + 64px); 114 | right: auto; 115 | bottom: auto; 116 | left: 50%; 117 | transform: translate(-50%, -50%); 118 | border: 1px solid #2a2c36; 119 | -webkit-user-select: none; 120 | -moz-user-select: none; 121 | -ms-user-select: none; 122 | user-select: none; 123 | background: url('./background.png') center center; 124 | z-index: 1; 125 | } 126 | 127 | -------------------------------------------------------------------------------- /projects/ai-2-pong/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Reinforcement Pong AI Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /projects/ai-2-pong/screenshot-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-2-pong/screenshot-small.png -------------------------------------------------------------------------------- /projects/ai-2-pong/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-2-pong/screenshot.png -------------------------------------------------------------------------------- /projects/ai-2-pong/source/Agent.mjs: -------------------------------------------------------------------------------- 1 | 2 | import { Brain } from './Brain.mjs'; 3 | 4 | 5 | 6 | const BRAIN_REFERENCE = { 7 | inputs: [ 8 | 0, 0.5, // paddle position 9 | 0, 0.8, // ball position 10 | 0.5, 0.2 // ball speed (1.0 == 25px/frame) 11 | ], 12 | outputs: [ 13 | 0.8 // targeted y position 14 | ] 15 | }; 16 | 17 | 18 | 19 | const Agent = function() { 20 | 21 | this.brain = new Brain(); 22 | 23 | 24 | // XXX: Brain needs a reference dataset 25 | this.brain.initialize( 26 | BRAIN_REFERENCE.inputs, 27 | BRAIN_REFERENCE.outputs 28 | ); 29 | 30 | }; 31 | 32 | Agent.prototype = { 33 | 34 | compute: function(inputs) { 35 | return this.brain.compute(inputs); 36 | }, 37 | 38 | learn: function(inputs, outputs) { 39 | return this.brain.learn(inputs, outputs); 40 | }, 41 | 42 | clone: function() { 43 | 44 | let clone = new Agent(); 45 | 46 | // This will copy/paste the exact same Brain 47 | // onto our clone. We need this method for 48 | // having non-linked properties, in case 49 | // this implementation is reused in an 50 | // Evolutionary algorithm. 51 | 52 | clone.brain.layers = JSON.parse(JSON.stringify(this.brain.layers)); 53 | 54 | 55 | return clone; 56 | 57 | } 58 | 59 | }; 60 | 61 | 62 | export { Agent }; 63 | 64 | -------------------------------------------------------------------------------- /projects/ai-2-pong/source/Ball.mjs: -------------------------------------------------------------------------------- 1 | 2 | const Ball = function(data) { 3 | 4 | this.x = 0; 5 | this.y = 0; 6 | this.vx = 0; 7 | this.vy = 0; 8 | 9 | this.last_hit = null; 10 | this.radius = 8; 11 | this.trail = []; 12 | 13 | this._t = 0; 14 | this._count = 0; 15 | 16 | if (data instanceof Object) { 17 | Object.assign(this, data); 18 | } 19 | 20 | }; 21 | 22 | 23 | Ball.prototype = { 24 | 25 | render: function(context) { 26 | 27 | let radius = this.radius; 28 | let trail = this.trail; 29 | 30 | 31 | context.beginPath(); 32 | context.fillStyle = '#f6336d'; 33 | context.arc( 34 | this.x, 35 | this.y, 36 | radius, 37 | 0, 38 | 2 * Math.PI 39 | ); 40 | context.fill(); 41 | 42 | 43 | for (let t = trail.length - 1, tl = trail.length; t >= 0; t--) { 44 | 45 | let pos = trail[t]; 46 | let a = t / tl; 47 | 48 | context.globalAlpha = a * 0.5; 49 | context.beginPath(); 50 | context.fillStyle = '#f6336d'; 51 | context.arc( 52 | pos.x, 53 | pos.y, 54 | a * radius, 55 | 0, 56 | 2 * Math.PI 57 | ); 58 | context.fill(); 59 | 60 | } 61 | 62 | 63 | context.globalAlpha = 1; 64 | 65 | }, 66 | 67 | update: function(game) { 68 | 69 | this.x += this.vx; 70 | this.y += this.vy; 71 | 72 | let x = this.x; 73 | let y = this.y; 74 | let r = this.radius; 75 | 76 | 77 | if (x - r <= 0) { 78 | this.alive = false; 79 | this.last_hit = null; 80 | } else if (x + r >= game.width) { 81 | this.alive = false; 82 | this.last_hit = null; 83 | } 84 | 85 | if (y - r <= 0) { 86 | this.y = r; 87 | this.vy = -1 * this.vy; 88 | this.last_hit = null; 89 | } else if (y + r >= game.height) { 90 | this.y = game.height - r; 91 | this.vy = -1 * this.vy; 92 | this.last_hit = null; 93 | } 94 | 95 | 96 | this._count++; 97 | 98 | 99 | if (this._count > 2) { 100 | 101 | 102 | if (this.trail.length < 8) { 103 | 104 | this.trail.push({ x: this.x, y: this.y }); 105 | 106 | } else { 107 | 108 | let pos = this.trail.splice(0, 1); 109 | 110 | pos.x = this.x; 111 | pos.y = this.y; 112 | 113 | this.trail.push(pos); 114 | 115 | } 116 | 117 | 118 | this._count = 0; 119 | 120 | } 121 | 122 | } 123 | 124 | }; 125 | 126 | 127 | 128 | export { Ball }; 129 | 130 | -------------------------------------------------------------------------------- /projects/ai-2-pong/source/Game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-2-pong/source/Game.png -------------------------------------------------------------------------------- /projects/ai-2-pong/source/Paddle.blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-2-pong/source/Paddle.blue.png -------------------------------------------------------------------------------- /projects/ai-2-pong/source/Paddle.red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-2-pong/source/Paddle.red.png -------------------------------------------------------------------------------- /projects/ai-2-pong/source/Twister.mjs: -------------------------------------------------------------------------------- 1 | 2 | const UPPER_MASK = 0x80000000; 3 | const LOWER_MASK = 0x7fffffff; 4 | const XOR_MATRIX = new Array(0x0, 0x9908b0df); 5 | 6 | const initialize = function(seed) { 7 | 8 | let index = 1; 9 | let N = this.N; 10 | let twister = this.twister; 11 | 12 | 13 | twister[0] = seed >>> 0; 14 | 15 | 16 | while (index < N) { 17 | 18 | let value = twister[index - 1] ^ (twister[index - 1] >>> 30); 19 | 20 | twister[index] = (((((value & 0xffff0000) >>> 16) * 1812433253) << 16) + (value & 0x0000ffff) * 1812433253) + index; 21 | twister[index] >>>= 0; 22 | 23 | index++; 24 | 25 | } 26 | 27 | this.index = index; 28 | 29 | }; 30 | 31 | const random_int32 = function() { 32 | 33 | let index = this.index; 34 | let twister = this.twister; 35 | let value = 0; 36 | let M = this.M; 37 | let N = this.N; 38 | 39 | 40 | if (index >= N) { 41 | 42 | let i = 0; 43 | 44 | if (index === N + 1) { 45 | initialize.call(this, 5489); 46 | } 47 | 48 | 49 | while (i < N - M) { 50 | 51 | value = (twister[i] & UPPER_MASK) | (twister[i + 1] & LOWER_MASK); 52 | twister[i] = twister[i + M] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 53 | 54 | i++; 55 | 56 | } 57 | 58 | while (i < N - 1) { 59 | 60 | value = (twister[i] & UPPER_MASK) | (twister[i + 1] & LOWER_MASK); 61 | twister[i] = twister[i + (M - N)] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 62 | 63 | i++; 64 | 65 | } 66 | 67 | 68 | value = (twister[N - 1] & UPPER_MASK) | (twister[0] & LOWER_MASK); 69 | twister[N - 1] = twister[M - 1] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 70 | 71 | this.index = 0; 72 | 73 | } 74 | 75 | 76 | value = twister[this.index++]; 77 | 78 | value ^= (value >>> 11); 79 | value ^= (value << 7) & 0x9d2c5680; 80 | value ^= (value << 15) & 0xefc60000; 81 | value ^= (value >>> 18); 82 | 83 | 84 | return value >>> 0; 85 | 86 | }; 87 | 88 | 89 | 90 | const Twister = function(seed) { 91 | 92 | seed = typeof seed === 'number' ? (seed | 0) : ((Math.random() * Number.MAX_SAFE_INTEGER) | 0); 93 | 94 | 95 | this.N = 624; 96 | this.M = 397; 97 | 98 | this.twister = new Array(this.N); 99 | this.index = this.N + 1; 100 | 101 | this.__seed = seed; 102 | 103 | 104 | initialize.call(this, seed); 105 | 106 | seed = null; 107 | 108 | }; 109 | 110 | 111 | Twister.prototype = { 112 | 113 | random: function() { 114 | 115 | return random_int32.call(this) * (1.0 / 4294967296.0); 116 | 117 | } 118 | 119 | }; 120 | 121 | 122 | 123 | export { Twister }; 124 | -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Pong Evolution 3 | 4 | This Game was a part of the AI Crash Course Workshop I held 5 | on various events. It's an in-Browser Implementation of a 6 | simple Evolutionary AI that can be scaled up with multiple 7 | Game Simulations in parallel in order to advance each Agent's 8 | Training and competitive advantages. 9 | 10 | 11 | ## License 12 | 13 | This project is licensed under [GNU GPL 3](./LICENSE_GPL3.txt) 14 | and is `(c) 2017-2021 Cookie Engineer`. 15 | 16 | -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/ai-3-pong-evolution.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-3-pong-evolution/ai-3-pong-evolution.zip -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-3-pong-evolution/background.png -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Reinforcement Pong AI Demo with Evolution 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/index.mjs: -------------------------------------------------------------------------------- 1 | 2 | import { Simulation } from './source/Simulation.mjs'; 3 | 4 | 5 | 6 | const SIMULATION = window.SIMULATION = new Simulation({ 7 | active: 0, 8 | games: 16 9 | }); 10 | 11 | SIMULATION.setFPS(300); 12 | SIMULATION.start(); 13 | SIMULATION.update(); 14 | SIMULATION.render(); 15 | 16 | 17 | 18 | let next_button = document.querySelector('aside button'); 19 | if (next_button !== null) { 20 | 21 | next_button.onclick = () => { 22 | SIMULATION.evolution.cycle(); 23 | }; 24 | 25 | next_button.removeAttribute('disabled'); 26 | 27 | } 28 | 29 | 30 | let menu = document.querySelector('aside menu'); 31 | if (menu !== null) { 32 | 33 | menu.innerHTML = SIMULATION.games.map((game, g) => { 34 | return '
  • '; 35 | }).join(''); 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/screenshot-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-3-pong-evolution/screenshot-small.png -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-3-pong-evolution/screenshot.png -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/source/Agent.mjs: -------------------------------------------------------------------------------- 1 | 2 | import { Brain } from './Brain.mjs'; 3 | 4 | 5 | 6 | const BRAIN_REFERENCE = { 7 | inputs: [ 8 | 0, 0.5, // paddle position 9 | 0, 0.8, // ball position 10 | 0.5, 0.2 // ball speed (1.0 == 25px/frame) 11 | ], 12 | outputs: [ 13 | 0.8 // targeted y position 14 | ] 15 | }; 16 | 17 | 18 | 19 | const Agent = function() { 20 | 21 | this.brain = new Brain(); 22 | this.fitness = 0; 23 | 24 | 25 | // XXX: Brain needs a reference dataset 26 | this.brain.initialize( 27 | BRAIN_REFERENCE.inputs, 28 | BRAIN_REFERENCE.outputs 29 | ); 30 | 31 | }; 32 | 33 | Agent.prototype = { 34 | 35 | compute: function(inputs) { 36 | return this.brain.compute(inputs); 37 | }, 38 | 39 | learn: function(inputs, outputs) { 40 | return this.brain.learn(inputs, outputs); 41 | }, 42 | 43 | clone: function() { 44 | 45 | let clone = new Agent(); 46 | 47 | // This will copy/paste the exact same Brain 48 | // onto our clone. We need this method for 49 | // having non-linked properties, in case 50 | // this implementation is reused in an 51 | // Evolutionary algorithm. 52 | 53 | clone.fitness = this.fitness; 54 | clone.brain.layers = JSON.parse(JSON.stringify(this.brain.layers)); 55 | 56 | 57 | return clone; 58 | 59 | }, 60 | 61 | crossover: function(agent) { 62 | 63 | let brain1 = this.brain.serialize(); 64 | let brain2 = agent.brain.serialize(); 65 | let brain3 = []; 66 | let brain4 = []; 67 | 68 | let split = Math.floor(Math.random() * brain1.length); 69 | let daughter = new Agent(); 70 | let son = new Agent(); 71 | 72 | 73 | for (let b = 0; b < brain1.length; b++) { 74 | 75 | if (b < split) { 76 | brain3.push(brain1[b]); 77 | brain4.push(brain2[b]); 78 | } else { 79 | brain3.push(brain2[b]); 80 | brain4.push(brain1[b]); 81 | } 82 | 83 | } 84 | 85 | 86 | daughter.brain.deserialize(brain3); 87 | son.brain.deserialize(brain4); 88 | 89 | 90 | return [ daughter, son ]; 91 | 92 | } 93 | 94 | }; 95 | 96 | 97 | export { Agent }; 98 | 99 | -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/source/Ball.mjs: -------------------------------------------------------------------------------- 1 | 2 | const Ball = function(data) { 3 | 4 | this.x = 0; 5 | this.y = 0; 6 | this.vx = 0; 7 | this.vy = 0; 8 | 9 | this.last_hit = null; 10 | this.radius = 8; 11 | this.trail = []; 12 | 13 | this._t = 0; 14 | this._count = 0; 15 | 16 | if (data instanceof Object) { 17 | Object.assign(this, data); 18 | } 19 | 20 | }; 21 | 22 | 23 | Ball.prototype = { 24 | 25 | render: function(context) { 26 | 27 | let radius = this.radius; 28 | let trail = this.trail; 29 | 30 | 31 | context.beginPath(); 32 | context.fillStyle = '#f6336d'; 33 | context.arc( 34 | this.x, 35 | this.y, 36 | radius, 37 | 0, 38 | 2 * Math.PI 39 | ); 40 | context.fill(); 41 | 42 | 43 | for (let t = trail.length - 1, tl = trail.length; t >= 0; t--) { 44 | 45 | let pos = trail[t]; 46 | let a = t / tl; 47 | 48 | context.globalAlpha = a * 0.5; 49 | context.beginPath(); 50 | context.fillStyle = '#f6336d'; 51 | context.arc( 52 | pos.x, 53 | pos.y, 54 | a * radius, 55 | 0, 56 | 2 * Math.PI 57 | ); 58 | context.fill(); 59 | 60 | } 61 | 62 | 63 | context.globalAlpha = 1; 64 | 65 | }, 66 | 67 | update: function(game) { 68 | 69 | this.x += this.vx; 70 | this.y += this.vy; 71 | 72 | let x = this.x; 73 | let y = this.y; 74 | let r = this.radius; 75 | 76 | 77 | if (x - r <= 0) { 78 | this.alive = false; 79 | this.last_hit = null; 80 | } else if (x + r >= game.width) { 81 | this.alive = false; 82 | this.last_hit = null; 83 | } 84 | 85 | if (y - r <= 0) { 86 | this.y = r; 87 | this.vy = -1 * this.vy; 88 | this.last_hit = null; 89 | } else if (y + r >= game.height) { 90 | this.y = game.height - r; 91 | this.vy = -1 * this.vy; 92 | this.last_hit = null; 93 | } 94 | 95 | 96 | this._count++; 97 | 98 | 99 | if (this._count > 2) { 100 | 101 | 102 | if (this.trail.length < 8) { 103 | 104 | this.trail.push({ x: this.x, y: this.y }); 105 | 106 | } else { 107 | 108 | let pos = this.trail.splice(0, 1); 109 | 110 | pos.x = this.x; 111 | pos.y = this.y; 112 | 113 | this.trail.push(pos); 114 | 115 | } 116 | 117 | 118 | this._count = 0; 119 | 120 | } 121 | 122 | } 123 | 124 | }; 125 | 126 | 127 | 128 | export { Ball }; 129 | 130 | -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/source/Game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-3-pong-evolution/source/Game.png -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/source/Paddle.blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-3-pong-evolution/source/Paddle.blue.png -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/source/Paddle.red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/ai-3-pong-evolution/source/Paddle.red.png -------------------------------------------------------------------------------- /projects/ai-3-pong-evolution/source/Twister.mjs: -------------------------------------------------------------------------------- 1 | 2 | const UPPER_MASK = 0x80000000; 3 | const LOWER_MASK = 0x7fffffff; 4 | const XOR_MATRIX = new Array(0x0, 0x9908b0df); 5 | 6 | const initialize = function(seed) { 7 | 8 | let index = 1; 9 | let N = this.N; 10 | let twister = this.twister; 11 | 12 | 13 | twister[0] = seed >>> 0; 14 | 15 | 16 | while (index < N) { 17 | 18 | let value = twister[index - 1] ^ (twister[index - 1] >>> 30); 19 | 20 | twister[index] = (((((value & 0xffff0000) >>> 16) * 1812433253) << 16) + (value & 0x0000ffff) * 1812433253) + index; 21 | twister[index] >>>= 0; 22 | 23 | index++; 24 | 25 | } 26 | 27 | this.index = index; 28 | 29 | }; 30 | 31 | const random_int32 = function() { 32 | 33 | let index = this.index; 34 | let twister = this.twister; 35 | let value = 0; 36 | let M = this.M; 37 | let N = this.N; 38 | 39 | 40 | if (index >= N) { 41 | 42 | let i = 0; 43 | 44 | if (index === N + 1) { 45 | initialize.call(this, 5489); 46 | } 47 | 48 | 49 | while (i < N - M) { 50 | 51 | value = (twister[i] & UPPER_MASK) | (twister[i + 1] & LOWER_MASK); 52 | twister[i] = twister[i + M] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 53 | 54 | i++; 55 | 56 | } 57 | 58 | while (i < N - 1) { 59 | 60 | value = (twister[i] & UPPER_MASK) | (twister[i + 1] & LOWER_MASK); 61 | twister[i] = twister[i + (M - N)] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 62 | 63 | i++; 64 | 65 | } 66 | 67 | 68 | value = (twister[N - 1] & UPPER_MASK) | (twister[0] & LOWER_MASK); 69 | twister[N - 1] = twister[M - 1] ^ (value >>> 1) ^ XOR_MATRIX[value & 0x1]; 70 | 71 | this.index = 0; 72 | 73 | } 74 | 75 | 76 | value = twister[this.index++]; 77 | 78 | value ^= (value >>> 11); 79 | value ^= (value << 7) & 0x9d2c5680; 80 | value ^= (value << 15) & 0xefc60000; 81 | value ^= (value >>> 18); 82 | 83 | 84 | return value >>> 0; 85 | 86 | }; 87 | 88 | 89 | 90 | const Twister = function(seed) { 91 | 92 | seed = typeof seed === 'number' ? (seed | 0) : ((Math.random() * Number.MAX_SAFE_INTEGER) | 0); 93 | 94 | 95 | this.N = 624; 96 | this.M = 397; 97 | 98 | this.twister = new Array(this.N); 99 | this.index = this.N + 1; 100 | 101 | this.__seed = seed; 102 | 103 | 104 | initialize.call(this, seed); 105 | 106 | seed = null; 107 | 108 | }; 109 | 110 | 111 | Twister.prototype = { 112 | 113 | random: function() { 114 | 115 | return random_int32.call(this) * (1.0 / 4294967296.0); 116 | 117 | } 118 | 119 | }; 120 | 121 | 122 | 123 | export { Twister }; 124 | -------------------------------------------------------------------------------- /projects/dns-proxy/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/dns-proxy/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/dns-proxy/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/dns-proxy/screenshot-01.png -------------------------------------------------------------------------------- /projects/dnsquery/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/dnsquery/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/dnsquery/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/dnsquery/screenshot-01.png -------------------------------------------------------------------------------- /projects/gibook-editor/gibook-editor.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/gibook-editor/gibook-editor.zip -------------------------------------------------------------------------------- /projects/gibook-editor/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/gibook-editor/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/gibook-editor/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/gibook-editor/screenshot-01.png -------------------------------------------------------------------------------- /projects/gibook-editor/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/gibook-editor/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/gibook-editor/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/gibook-editor/screenshot-02.png -------------------------------------------------------------------------------- /projects/git-cockpit/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-cockpit/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/git-cockpit/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-cockpit/screenshot-01.png -------------------------------------------------------------------------------- /projects/git-cockpit/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-cockpit/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/git-cockpit/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-cockpit/screenshot-02.png -------------------------------------------------------------------------------- /projects/git-work/git-work.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-work/git-work.zip -------------------------------------------------------------------------------- /projects/git-work/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-work/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/git-work/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-work/screenshot-01.png -------------------------------------------------------------------------------- /projects/git-work/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-work/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/git-work/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-work/screenshot-02.png -------------------------------------------------------------------------------- /projects/git-work/screenshot-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-work/screenshot-03-small.png -------------------------------------------------------------------------------- /projects/git-work/screenshot-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/git-work/screenshot-03.png -------------------------------------------------------------------------------- /projects/github-scrumboard/github-scrumboard-0.0.4.crx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/github-scrumboard/github-scrumboard-0.0.4.crx -------------------------------------------------------------------------------- /projects/github-scrumboard/github-scrumboard.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/github-scrumboard/github-scrumboard.zip -------------------------------------------------------------------------------- /projects/github-scrumboard/github_scrumboard-0.0.4.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/github-scrumboard/github_scrumboard-0.0.4.xpi -------------------------------------------------------------------------------- /projects/github-scrumboard/screencast-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/github-scrumboard/screencast-01-small.png -------------------------------------------------------------------------------- /projects/github-scrumboard/screencast-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/github-scrumboard/screencast-01.gif -------------------------------------------------------------------------------- /projects/gnome-shell-extension-outta-space/gnome-shell-extension-outta-space.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/gnome-shell-extension-outta-space/gnome-shell-extension-outta-space.zip -------------------------------------------------------------------------------- /projects/jquery-desktop/jquery-desktop.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/jquery-desktop/jquery-desktop.zip -------------------------------------------------------------------------------- /projects/lycheejs-breeder/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-breeder/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/lycheejs-breeder/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-breeder/screenshot-01.png -------------------------------------------------------------------------------- /projects/lycheejs-breeder/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-breeder/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/lycheejs-breeder/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-breeder/screenshot-02.png -------------------------------------------------------------------------------- /projects/lycheejs-breeder/screenshot-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-breeder/screenshot-03-small.png -------------------------------------------------------------------------------- /projects/lycheejs-breeder/screenshot-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-breeder/screenshot-03.png -------------------------------------------------------------------------------- /projects/lycheejs-engine/lycheejs.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/lycheejs.zip -------------------------------------------------------------------------------- /projects/lycheejs-engine/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/lycheejs-engine/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/screenshot-01.png -------------------------------------------------------------------------------- /projects/lycheejs-engine/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/lycheejs-engine/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/screenshot-02.png -------------------------------------------------------------------------------- /projects/lycheejs-engine/screenshot-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/screenshot-03-small.png -------------------------------------------------------------------------------- /projects/lycheejs-engine/screenshot-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/screenshot-03.png -------------------------------------------------------------------------------- /projects/lycheejs-engine/screenshot-04-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/screenshot-04-small.png -------------------------------------------------------------------------------- /projects/lycheejs-engine/screenshot-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-engine/screenshot-04.png -------------------------------------------------------------------------------- /projects/lycheejs-fertilizer/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-fertilizer/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/lycheejs-fertilizer/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-fertilizer/screenshot-01.png -------------------------------------------------------------------------------- /projects/lycheejs-fertilizer/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-fertilizer/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/lycheejs-fertilizer/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-fertilizer/screenshot-02.png -------------------------------------------------------------------------------- /projects/lycheejs-harvester/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-harvester/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/lycheejs-harvester/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-harvester/screenshot-01.png -------------------------------------------------------------------------------- /projects/lycheejs-harvester/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-harvester/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/lycheejs-harvester/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-harvester/screenshot-02.png -------------------------------------------------------------------------------- /projects/lycheejs-harvester/screenshot-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-harvester/screenshot-03-small.png -------------------------------------------------------------------------------- /projects/lycheejs-harvester/screenshot-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/lycheejs-harvester/screenshot-03.png -------------------------------------------------------------------------------- /projects/me-want-cookies/me-want-cookies.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/me-want-cookies/me-want-cookies.zip -------------------------------------------------------------------------------- /projects/me-want-cookies/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/me-want-cookies/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/me-want-cookies/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/me-want-cookies/screenshot-01.png -------------------------------------------------------------------------------- /projects/pacman-backup/pacman-backup-1.0.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/pacman-backup/pacman-backup-1.0.0.zip -------------------------------------------------------------------------------- /projects/pacman-backup/pacman-backup-2.0.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/pacman-backup/pacman-backup-2.0.1.zip -------------------------------------------------------------------------------- /projects/patienteninfo-service/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/patienteninfo-service/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/patienteninfo-service/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/patienteninfo-service/screenshot-01.png -------------------------------------------------------------------------------- /projects/patienteninfo-service/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/patienteninfo-service/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/patienteninfo-service/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/patienteninfo-service/screenshot-02.png -------------------------------------------------------------------------------- /projects/polyfillr/polyfillr.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/polyfillr/polyfillr.zip -------------------------------------------------------------------------------- /projects/polyfillr/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/polyfillr/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/polyfillr/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/polyfillr/screenshot-01.png -------------------------------------------------------------------------------- /projects/polyfillr/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/polyfillr/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/polyfillr/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/polyfillr/screenshot-02.png -------------------------------------------------------------------------------- /projects/research/research.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/research/research.zip -------------------------------------------------------------------------------- /projects/research/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/research/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/research/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/research/screenshot-01.png -------------------------------------------------------------------------------- /projects/research/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/research/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/research/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/research/screenshot-02.png -------------------------------------------------------------------------------- /projects/research/screenshot-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/research/screenshot-03-small.png -------------------------------------------------------------------------------- /projects/research/screenshot-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/research/screenshot-03.png -------------------------------------------------------------------------------- /projects/skye-drone/skye-drone-01-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/skye-drone/skye-drone-01-small.jpg -------------------------------------------------------------------------------- /projects/skye-drone/skye-drone-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/skye-drone/skye-drone-01.jpg -------------------------------------------------------------------------------- /projects/skye-drone/skye-drone-02-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/skye-drone/skye-drone-02-small.jpg -------------------------------------------------------------------------------- /projects/skye-drone/skye-drone-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/skye-drone/skye-drone-02.jpg -------------------------------------------------------------------------------- /projects/stealth/stealth-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stealth/stealth-01-small.png -------------------------------------------------------------------------------- /projects/stealth/stealth-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stealth/stealth-01.png -------------------------------------------------------------------------------- /projects/stealth/stealth-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stealth/stealth-02-small.png -------------------------------------------------------------------------------- /projects/stealth/stealth-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stealth/stealth-02.png -------------------------------------------------------------------------------- /projects/stealth/stealth-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stealth/stealth-03-small.png -------------------------------------------------------------------------------- /projects/stealth/stealth-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stealth/stealth-03.png -------------------------------------------------------------------------------- /projects/stealth/stealth-04-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stealth/stealth-04-small.png -------------------------------------------------------------------------------- /projects/stealth/stealth-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stealth/stealth-04.png -------------------------------------------------------------------------------- /projects/stegit/stegit.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/stegit/stegit.zip -------------------------------------------------------------------------------- /projects/switchine/switchine-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine-01-small.png -------------------------------------------------------------------------------- /projects/switchine/switchine-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine-01.png -------------------------------------------------------------------------------- /projects/switchine/switchine-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine-02-small.png -------------------------------------------------------------------------------- /projects/switchine/switchine-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine-02.png -------------------------------------------------------------------------------- /projects/switchine/switchine-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine-03-small.png -------------------------------------------------------------------------------- /projects/switchine/switchine-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine-03.png -------------------------------------------------------------------------------- /projects/switchine/switchine-04-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine-04-small.png -------------------------------------------------------------------------------- /projects/switchine/switchine-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine-04.png -------------------------------------------------------------------------------- /projects/switchine/switchine.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/switchine/switchine.zip -------------------------------------------------------------------------------- /projects/webmail/webmail.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/webmail/webmail.zip -------------------------------------------------------------------------------- /projects/webslide-me/webslide-me.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/webslide-me/webslide-me.zip -------------------------------------------------------------------------------- /projects/zynga-jukebox/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-jukebox/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/zynga-jukebox/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-jukebox/screenshot-01.png -------------------------------------------------------------------------------- /projects/zynga-jukebox/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-jukebox/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/zynga-jukebox/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-jukebox/screenshot-02.png -------------------------------------------------------------------------------- /projects/zynga-jukebox/screenshot-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-jukebox/screenshot-03-small.png -------------------------------------------------------------------------------- /projects/zynga-jukebox/screenshot-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-jukebox/screenshot-03.png -------------------------------------------------------------------------------- /projects/zynga-jukebox/zynga-jukebox.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-jukebox/zynga-jukebox.zip -------------------------------------------------------------------------------- /projects/zynga-speedrun/css/library.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family:Helvetica, sans-serif; 3 | } 4 | 5 | .lib-abs { 6 | position:absolute; 7 | } 8 | 9 | .lib-shadow { 10 | box-shadow:inset 0px 0px 20px #000; 11 | -moz-box-shadow:inset 0px 0px 20px #000; 12 | -webkit-box-shadow:inset 0px 0px 20px #000; 13 | } -------------------------------------------------------------------------------- /projects/zynga-speedrun/js/init.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var Benchmark; 4 | $(document).ready(function() { 5 | 6 | // initialize benchmark 7 | Benchmark = new z.Benchmark(); 8 | 9 | Benchmark.parseHash(); 10 | 11 | // track performance statistics 12 | var stats = { 13 | fps: $('#ui-stats-fps')[0], 14 | pps: $('#ui-stats-pps')[0], 15 | paints: $('#ui-stats-paints')[0] 16 | }; 17 | 18 | window.setInterval(function() { 19 | stats.fps.innerHTML = Benchmark.statistics.fps; // || Infinity; 20 | stats.pps.innerHTML = Benchmark.statistics.pps; // || Infinity; 21 | stats.paints.innerHTML = Benchmark.statistics.paints || 0; 22 | }, 100); 23 | 24 | 25 | }); 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /projects/zynga-speedrun/js/init_ui.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | // create little tab dots and mark current visible as active 4 | function switchUITabs(direction) { 5 | 6 | // update tabs visiblity 7 | var curTab = $('.ui-sidebar-tab.visible').removeClass('visible'); 8 | var nextTab = curTab[direction]('.ui-sidebar-tab'); 9 | 10 | // add 'visible' class to make tab visible, fall back to current if no prev/next 11 | nextTab = (nextTab.length ? nextTab : curTab).addClass('visible'); 12 | 13 | // update tabs index indicator 14 | $('#ui-sidebar-tabs > *').removeClass().eq(nextTab.index()).addClass('active'); 15 | 16 | 17 | } 18 | 19 | // update the sidebar form from the defaults/hash tag 20 | for (var s in Benchmark.options) { 21 | z.updateUIFromOption(s, Benchmark.options[s]); 22 | } 23 | 24 | // set up "update" button 25 | $('#ui-update').click(function() { 26 | z.updateOptionsFromUI(); 27 | return false; 28 | }); 29 | 30 | // set up sliders 31 | $('.ui-slider').change(function() { 32 | $(this.getAttribute('data-info')).text(this.value.match(/\./) ? this.value.substr(0, 3) : this.value); 33 | }); 34 | 35 | // prev/forward tabs 36 | $('#ui-sidebar-tabs-prev, #ui-sidebar-tabs-next').click(function() { 37 | switchUITabs(this.id.split('-')[3]); 38 | }); 39 | 40 | var tabIndex = $('#ui-sidebar-tabs'); 41 | $('.ui-sidebar-tab').each(function() { 42 | $('
  • ').attr('data-href', '#' + this.id).addClass(this.className.match(/visible/) && 'active').appendTo(tabIndex); 43 | }); 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /projects/zynga-speedrun/js/modules/FPS.js: -------------------------------------------------------------------------------- 1 | var FPS; 2 | (function() { 3 | 4 | z.FPS = function() { 5 | this.context = document.createElement('div'); 6 | this.context.id = 'fpscounter'; 7 | 8 | this._init(); 9 | }; 10 | 11 | z.FPS.prototype = { 12 | 13 | _init: function() { 14 | 15 | // webkit keyframes for animation 16 | document.styleSheets[0].insertRule('@-webkit-keyframes fpscounter { from{} to{} }'); 17 | 18 | this.context.style.cssText = 'position:absolute;top:0px;left:0px;background:black;color:white;-webkit-animation:fpscounter 16.6ms infinite;'; 19 | document.body.appendChild(this.context); 20 | 21 | this.__lastLoop = +new Date(); 22 | 23 | var that = this; 24 | this.context.addEventListener('webkitAnimationIteration', function(event) { 25 | that.__loop(); 26 | }); 27 | 28 | }, 29 | 30 | __loop: function() { 31 | 32 | var now = +new Date(), 33 | fps = Math.floor(1000 / (now - this.__lastLoop)); 34 | 35 | this.log(fps); 36 | this.__lastLoop = now; 37 | 38 | }, 39 | 40 | log: function(value) { 41 | this.context.innerText = value; 42 | } 43 | 44 | }; 45 | 46 | FPS = new z.FPS(); 47 | 48 | })(); -------------------------------------------------------------------------------- /projects/zynga-speedrun/js/modules/benchmark.control.js: -------------------------------------------------------------------------------- 1 | $.extend(z.Benchmark.prototype, { 2 | 3 | start: function() { 4 | 5 | // width and height caching 6 | this.width = this.context.offsetWidth; 7 | this.height = this.context.offsetHeight; 8 | 9 | // create dynamic nodes 10 | var i, obj; 11 | for (i = 0; i < this.options.dynamicamount; i++) { 12 | obj = this._createNode(); 13 | this.dynamicNodes.push(obj); 14 | this.context.appendChild(obj.node); 15 | this.runPlugins(obj); 16 | } 17 | 18 | // create static nodes 19 | for (i = 0; i < this.options.staticamount; i++) { 20 | obj = this._createNode(); 21 | this.staticNodes.push(obj); 22 | this.context.appendChild(obj.node); 23 | this.runPlugins(obj); 24 | 25 | // initially run setPosition on the static object 26 | this.setPosition(obj); 27 | 28 | } 29 | 30 | // only update when context was reset 31 | if (!this._running) { 32 | 33 | this._running = true; 34 | this.statistics.started = +new Date(); 35 | 36 | // initialize the renderLoop only on initialization 37 | if (!this._initialized) { 38 | 39 | this._initialized = true; 40 | this.__lastLoopTime = +new Date(); 41 | this._renderLoop(); 42 | 43 | } 44 | } 45 | 46 | }, 47 | 48 | stop: function(msg) { 49 | 50 | // stop renderLoop 51 | this._running = false; 52 | 53 | this.context.style.cssText = 'text-align:center;color:white;background:black'; 54 | 55 | // Bug: transforms are not reset via cssText 56 | this.context.style[z.css.transform] = ' '; 57 | 58 | this.context.innerHTML = 'Benchmark was stopped.
    ' + (msg || ''); 59 | 60 | }, 61 | 62 | reset: function() { 63 | 64 | // stop renderLoop 65 | this._running = false; 66 | 67 | // reset DOM representation 68 | this.context.innerHTML = ' '; 69 | this.context.style.cssText = ''; 70 | 71 | // reset cache 72 | this.staticNodes = []; 73 | this.dynamicNodes = []; 74 | 75 | // reset statistics 76 | this.statistics.paints = 0; 77 | 78 | }, 79 | 80 | update: function() { 81 | 82 | if (!this.options.width) { 83 | this.options.width = this.context.offsetWidth; 84 | } else { 85 | this.context.style.width = this.options.width + 'px'; 86 | } 87 | 88 | if (!this.options.height) { 89 | this.options.height = this.context.offsetHeight; 90 | } else { 91 | this.context.style.height = this.options.height + 'px'; 92 | } 93 | 94 | } 95 | 96 | }); 97 | -------------------------------------------------------------------------------- /projects/zynga-speedrun/js/modules/benchmark.hash.js: -------------------------------------------------------------------------------- 1 | $.extend(z.Benchmark.prototype, { 2 | 3 | parseHash: function(hash) { 4 | 5 | if (!hash || !hash.length) { 6 | hash = window.location.hash; 7 | } 8 | 9 | if (hash.match(/#/)) { 10 | hash = hash.split(/#/)[1]; 11 | } 12 | 13 | var hashArr = hash.split(','), 14 | newOptions = {}; 15 | 16 | // we got something to parse 17 | if (hashArr.length) { 18 | 19 | for (var h = 0, l = hashArr.length; h < l; h++) { 20 | var _tmp = hashArr[h].split('='); 21 | var key = _tmp[0], 22 | val = _tmp[1]; 23 | 24 | newOptions[key] = !isNaN(parseInt(val, 10)) ? parseInt(val, 10) : val; 25 | } 26 | 27 | } 28 | 29 | this.setOptions(newOptions); 30 | 31 | }, 32 | 33 | getHash: function() { 34 | 35 | var hashArr = []; 36 | for (var s in this.options) { 37 | 38 | if (this.options[s] !== this.defaults[s]) { 39 | hashArr.push(s + '=' + this.options[s]); 40 | } 41 | } 42 | 43 | return hashArr.join(','); 44 | 45 | }, 46 | 47 | updateHash: function() { 48 | window.location.hash = this.getHash(); 49 | } 50 | 51 | }); 52 | -------------------------------------------------------------------------------- /projects/zynga-speedrun/res/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-speedrun/res/debug.png -------------------------------------------------------------------------------- /projects/zynga-speedrun/screenshot-01-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-speedrun/screenshot-01-small.png -------------------------------------------------------------------------------- /projects/zynga-speedrun/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-speedrun/screenshot-01.png -------------------------------------------------------------------------------- /projects/zynga-speedrun/screenshot-02-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-speedrun/screenshot-02-small.png -------------------------------------------------------------------------------- /projects/zynga-speedrun/screenshot-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-speedrun/screenshot-02.png -------------------------------------------------------------------------------- /projects/zynga-speedrun/screenshot-03-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-speedrun/screenshot-03-small.png -------------------------------------------------------------------------------- /projects/zynga-speedrun/screenshot-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-speedrun/screenshot-03.png -------------------------------------------------------------------------------- /projects/zynga-speedrun/zynga-speedrun.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/projects/zynga-speedrun/zynga-speedrun.zip -------------------------------------------------------------------------------- /talks/2012-ongamestart/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/talks/2012-ongamestart/screenshot-01.png -------------------------------------------------------------------------------- /talks/2014-jsconf-eu/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/talks/2014-jsconf-eu/screenshot-01.png -------------------------------------------------------------------------------- /talks/2014-karlsruhejs/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/talks/2014-karlsruhejs/screenshot-01.png -------------------------------------------------------------------------------- /talks/2016-frankfurtjs/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/talks/2016-frankfurtjs/screenshot-01.png -------------------------------------------------------------------------------- /talks/2018-frankfurt-datascience/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/talks/2018-frankfurt-datascience/screenshot-01.png -------------------------------------------------------------------------------- /toolchain/actions/DecryptCV.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import "cookie.engineer/console" 4 | import "cookie.engineer/cvs" 5 | import "os" 6 | import "path/filepath" 7 | 8 | func DecryptCV(folder string, password string, output string) bool { 9 | 10 | var result bool = false 11 | 12 | console.Group("actions/DecryptCV") 13 | 14 | filename := cvs.DeriveFilename(password) 15 | 16 | cwd, err0 := os.Getwd() 17 | 18 | if err0 == nil { 19 | 20 | prettyname, err1 := filepath.Rel(cwd, folder + "/" + filename) 21 | 22 | if err1 == nil { 23 | console.Log("Input: " + prettyname) 24 | console.Log("Output: " + output) 25 | } 26 | 27 | } else { 28 | console.Log("Input: " + folder + "/" + filename) 29 | console.Log("Output: " + output) 30 | } 31 | 32 | encrypted, err1 := os.ReadFile(folder + "/" + filename) 33 | 34 | if err1 == nil { 35 | 36 | buffer := cvs.Decrypt(encrypted, password) 37 | 38 | if len(buffer) > 0 { 39 | 40 | err2 := os.WriteFile(output, buffer, 0666) 41 | 42 | if err2 == nil { 43 | result = true 44 | } 45 | 46 | } 47 | 48 | } 49 | 50 | console.GroupEndResult(result, "actions/DecryptCV") 51 | 52 | return result 53 | 54 | } 55 | -------------------------------------------------------------------------------- /toolchain/actions/EncryptCV.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import "cookie.engineer/console" 4 | import "cookie.engineer/cvs" 5 | import "os" 6 | import "path/filepath" 7 | 8 | func EncryptCV(folder string, password string, input string) bool { 9 | 10 | var result bool = false 11 | 12 | console.Group("actions/EncryptCV") 13 | 14 | filename := cvs.DeriveFilename(password) 15 | 16 | cwd, err0 := os.Getwd() 17 | 18 | if err0 == nil { 19 | 20 | prettyname, err1 := filepath.Rel(cwd, folder + "/" + filename) 21 | 22 | if err1 == nil { 23 | console.Log("Input: " + input) 24 | console.Log("Output: " + prettyname) 25 | } 26 | 27 | } else { 28 | console.Log("Input: " + input) 29 | console.Log("Output: " + folder + "/" + filename) 30 | } 31 | 32 | buffer, err1 := os.ReadFile(input) 33 | 34 | if err1 == nil { 35 | 36 | encrypted := cvs.Encrypt(buffer, password) 37 | 38 | if len(encrypted) > 0 { 39 | 40 | err2 := os.WriteFile(folder + "/" + filename, encrypted, 0666) 41 | 42 | if err2 == nil { 43 | result = true 44 | } 45 | 46 | } 47 | 48 | } 49 | 50 | console.GroupEndResult(result, "actions/EncryptCV") 51 | 52 | return result 53 | 54 | } 55 | -------------------------------------------------------------------------------- /toolchain/actions/Render.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import "cookie.engineer/routes" 4 | import "strings" 5 | 6 | func Render(root string, file string) bool { 7 | 8 | var result bool = false 9 | 10 | if !strings.Contains(file, "/") && strings.HasSuffix(file, ".md") { 11 | result = routes.RenderArticle(root, file) 12 | } 13 | 14 | return result 15 | 16 | } 17 | -------------------------------------------------------------------------------- /toolchain/actions/Serve.go: -------------------------------------------------------------------------------- 1 | package actions 2 | 3 | import "cookie.engineer/routes" 4 | import "cookie.engineer/utils" 5 | import "net/http" 6 | import "os" 7 | import "strconv" 8 | import "strings" 9 | 10 | func Serve(root string, port uint) bool { 11 | 12 | var result bool = false 13 | 14 | fsrv := http.FileServer(http.FS(os.DirFS(root))) 15 | http.Handle("/", fsrv) 16 | 17 | http.HandleFunc("/weblog/index.html", func(response http.ResponseWriter, request *http.Request) { 18 | 19 | if request.Method == http.MethodGet { 20 | 21 | routes.RenderArticles(root) 22 | routes.RenderFeed(root) 23 | routes.RenderIndex(root) 24 | 25 | routes.ServeFile(root, "weblog/index.html", response, request) 26 | 27 | } else { 28 | 29 | response.Header().Set("Content-Type", "text/html") 30 | response.WriteHeader(http.StatusMethodNotAllowed) 31 | response.Write([]byte{}) 32 | 33 | } 34 | 35 | }) 36 | 37 | http.HandleFunc("/weblog/articles/*.md", func(response http.ResponseWriter, request *http.Request) { 38 | routes.ServeArticleIndex(root, response, request) 39 | }) 40 | 41 | http.HandleFunc("/weblog/articles/{file}", func(response http.ResponseWriter, request *http.Request) { 42 | 43 | if request.Method == http.MethodGet { 44 | 45 | file := request.PathValue("file") 46 | 47 | if strings.HasSuffix(file, ".md") { 48 | routes.ServeArticle(root, response, request) 49 | } else if strings.HasSuffix(file, ".html") { 50 | routes.ServeArticle(root, response, request) 51 | } else { 52 | routes.ServeFile(root, "weblog/articles/"+file, response, request) 53 | } 54 | 55 | } else if request.Method == http.MethodPost { 56 | 57 | file := request.PathValue("file") 58 | 59 | if strings.HasSuffix(file, ".md") { 60 | routes.ModifyFile(root, "weblog/articles/"+file, response, request) 61 | } else { 62 | utils.RespondWith(response, file, http.StatusMethodNotAllowed) 63 | } 64 | 65 | } else if request.Method == http.MethodDelete { 66 | 67 | file := request.PathValue("file") 68 | 69 | if strings.HasPrefix(file, "draft-") && strings.HasSuffix(file, ".md") { 70 | routes.RemoveFile(root, "weblog/articles/"+file, response, request) 71 | } else { 72 | utils.RespondWith(response, file, http.StatusMethodNotAllowed) 73 | } 74 | 75 | } else { 76 | utils.RespondWith(response, request.PathValue("file"), http.StatusMethodNotAllowed) 77 | } 78 | 79 | }) 80 | 81 | err1 := http.ListenAndServe(":"+strconv.FormatUint(uint64(port), 10), nil) 82 | 83 | if err1 == nil { 84 | result = true 85 | } 86 | 87 | return result 88 | 89 | } 90 | -------------------------------------------------------------------------------- /toolchain/cmds/cv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "cookie.engineer/console" 4 | import "cookie.engineer/actions" 5 | import "os" 6 | import "strings" 7 | 8 | func showHelp() { 9 | 10 | console.Info("") 11 | console.Info("CV Encrypter/Decrypter Tool") 12 | console.Info("") 13 | 14 | console.Group("Usage: [Action] [Password]") 15 | console.GroupEnd("-----") 16 | 17 | console.Group("Examples") 18 | console.Log("") 19 | console.Log("# Write decrypted CV to ../cv/source/DECRYPTED.cv") 20 | console.Log("cv decrypt \"password\";") 21 | console.Log("") 22 | console.Log("# Write encrypted CV to ../cv/source/.cv") 23 | console.Log("cv encrypt \"password\";") 24 | console.Log("") 25 | console.GroupEnd("--------") 26 | 27 | } 28 | 29 | func main() { 30 | 31 | action := "" 32 | password := "" 33 | 34 | if len(os.Args) == 3 { 35 | 36 | if os.Args[1] == "encrypt" { 37 | 38 | if os.Args[2] != "" { 39 | action = "encrypt" 40 | password = os.Args[2] 41 | } 42 | 43 | } else if os.Args[1] == "decrypt" { 44 | 45 | if os.Args[2] != "" { 46 | action = "decrypt" 47 | password = os.Args[2] 48 | } 49 | 50 | } 51 | 52 | } 53 | 54 | cwd, err1 := os.Getwd() 55 | 56 | if err1 == nil { 57 | 58 | if strings.HasSuffix(cwd, "/toolchain") { 59 | cwd = cwd[0:len(cwd)-10] 60 | } 61 | 62 | if action == "encrypt" { 63 | 64 | result := actions.EncryptCV(cwd + "/cv/source", password, cwd + "/cv/source/DECRYPTED.cv") 65 | 66 | if result == true { 67 | os.Exit(0) 68 | } else { 69 | os.Exit(1) 70 | } 71 | 72 | } else if action == "decrypt" { 73 | 74 | result := actions.DecryptCV(cwd + "/cv/source", password, cwd + "/cv/source/DECRYPTED.cv") 75 | 76 | if result == true { 77 | os.Exit(0) 78 | } else { 79 | os.Exit(1) 80 | } 81 | 82 | } else { 83 | showHelp() 84 | os.Exit(1) 85 | } 86 | 87 | } else { 88 | showHelp() 89 | os.Exit(1) 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /toolchain/cmds/render/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "cookie.engineer/console" 4 | import "cookie.engineer/actions" 5 | import "os" 6 | import "strings" 7 | 8 | func showUsage() { 9 | 10 | console.Group("Usage:") 11 | console.Log("render .md") 12 | console.Log("$PWD must be the cookie.engineer/ folder") 13 | console.GroupEnd("------") 14 | 15 | } 16 | 17 | func main() { 18 | 19 | cwd, err1 := os.Getwd() 20 | 21 | if err1 == nil { 22 | 23 | if strings.HasSuffix(cwd, "/server") { 24 | cwd = strings.TrimSpace(cwd[0:len(cwd)-7]) 25 | } 26 | 27 | if strings.HasSuffix(cwd, "/toolchain") { 28 | cwd = strings.TrimSpace(cwd[0:len(cwd)-10]) 29 | } 30 | 31 | file := "" 32 | 33 | if len(os.Args) == 2 { 34 | 35 | if strings.HasSuffix(os.Args[1], ".md") { 36 | 37 | file = os.Args[1] 38 | 39 | if strings.Contains(file, "/") { 40 | file = strings.TrimSpace(file[strings.LastIndex(file, "/")+1:]) 41 | } 42 | 43 | } 44 | 45 | } 46 | 47 | if file != "" { 48 | 49 | result := actions.Render(cwd, file) 50 | 51 | if result == true { 52 | os.Exit(0) 53 | } else { 54 | os.Exit(1) 55 | } 56 | 57 | } else { 58 | 59 | showUsage() 60 | os.Exit(1) 61 | 62 | } 63 | 64 | } else { 65 | 66 | showUsage() 67 | os.Exit(1) 68 | 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /toolchain/cmds/serve/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "cookie.engineer/console" 4 | import "cookie.engineer/actions" 5 | import "os" 6 | import "strings" 7 | 8 | func main() { 9 | 10 | cwd, err1 := os.Getwd() 11 | 12 | if err1 == nil { 13 | 14 | if strings.HasSuffix(cwd, "/server") { 15 | cwd = strings.TrimSpace(cwd[0:len(cwd)-7]) 16 | } 17 | 18 | if strings.HasSuffix(cwd, "/toolchain") { 19 | cwd = strings.TrimSpace(cwd[0:len(cwd)-10]) 20 | } 21 | 22 | console.Log("Listening on http://localhost:3000") 23 | 24 | actions.Serve(cwd, 3000) 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /toolchain/console/Clear.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | 5 | func Clear() { 6 | 7 | var has_errors bool = false 8 | 9 | for m := 0; m < len(MESSAGES); m++ { 10 | 11 | if MESSAGES[m].Method == "Error" { 12 | has_errors = true 13 | break 14 | } 15 | 16 | } 17 | 18 | MESSAGES = append(MESSAGES, NewMessage("Clear", "")) 19 | 20 | if has_errors == false { 21 | 22 | // clear screen and reset cursor 23 | os.Stdout.WriteString("\u001b[2J\u001b[0f") 24 | 25 | // clear scroll buffer 26 | os.Stdout.WriteString("\u001b[3J") 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /toolchain/console/ClearLines.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | import "strconv" 5 | 6 | func ClearLines(number int) { 7 | 8 | if number < 32 { 9 | 10 | // move up x lines 11 | os.Stdout.WriteString("\033[" + strconv.Itoa(number) + "A") 12 | 13 | // clear from cursor to end of screen 14 | os.Stdout.WriteString("\033[J") 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /toolchain/console/Disable.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | func Disable(feature int) { 4 | 5 | if feature == FeatureAll { 6 | 7 | for feature := range features { 8 | features[feature] = false 9 | } 10 | 11 | } else { 12 | 13 | _, ok := features[feature] 14 | 15 | if ok == true { 16 | features[feature] = false 17 | } 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /toolchain/console/Enable.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | func Enable(feature int) { 4 | 5 | if feature == FeatureAll { 6 | 7 | for feature := range features { 8 | features[feature] = false 9 | } 10 | 11 | } else { 12 | 13 | _, ok := features[feature] 14 | 15 | if ok == true { 16 | features[feature] = true 17 | } 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /toolchain/console/Error.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | import "strings" 5 | 6 | func Error(message string) { 7 | 8 | if features[FeatureError] == true { 9 | 10 | message = sanitize(message) 11 | offset := toOffset() 12 | MESSAGES = append(MESSAGES, NewMessage("Error", message)) 13 | 14 | if strings.Contains(message, "\n") { 15 | 16 | var lines = strings.Split(message, "\n") 17 | 18 | if COLORS == true { 19 | 20 | for l := 0; l < len(lines); l++ { 21 | os.Stderr.WriteString("\u001b[41m" + offset + toSeparator(lines[l]) + lines[l] + "\u001b[K\n") 22 | } 23 | 24 | os.Stderr.WriteString("\u001b[0m") 25 | 26 | } else { 27 | 28 | for l := 0; l < len(lines); l++ { 29 | os.Stderr.WriteString(offset + toSeparator(lines[l]) + lines[l] + "\n") 30 | } 31 | 32 | } 33 | 34 | } else { 35 | 36 | if COLORS == true { 37 | os.Stderr.WriteString("\u001b[41m" + offset + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 38 | } else { 39 | os.Stderr.WriteString(offset + toSeparator(message) + message + "\n") 40 | } 41 | 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /toolchain/console/Group.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | 5 | func Group(message string) { 6 | 7 | if features[FeatureGroup] == true { 8 | 9 | offset := toOffset() 10 | message = sanitize(message) 11 | MESSAGES = append(MESSAGES, NewMessage("Group", message)) 12 | OFFSET++ 13 | 14 | if COLORS == true { 15 | os.Stdout.WriteString("\u001b[40m" + offset + "/" + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 16 | } else { 17 | os.Stdout.WriteString(offset + "/" + toSeparator(message) + message + "\n") 18 | } 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /toolchain/console/GroupEnd.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | 5 | func GroupEnd(message string) { 6 | 7 | if features[FeatureGroup] == true { 8 | 9 | if OFFSET > 0 { 10 | OFFSET-- 11 | } 12 | 13 | message = sanitize(message) 14 | offset := toOffset() 15 | MESSAGES = append(MESSAGES, NewMessage("GroupEnd", message)) 16 | 17 | if COLORS == true { 18 | os.Stdout.WriteString("\u001b[40m" + offset + "\\" + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 19 | } else { 20 | os.Stdout.WriteString(offset + "\\" + toSeparator(message) + message + "\n") 21 | } 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /toolchain/console/GroupEndResult.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | import "strings" 5 | 6 | func GroupEndResult(result bool, message string) { 7 | 8 | if features[FeatureGroup] == true { 9 | 10 | if OFFSET > 0 { 11 | OFFSET-- 12 | } 13 | 14 | message = sanitize(message) 15 | offset := toOffset() 16 | 17 | if result == true { 18 | 19 | message = strings.TrimSpace(message + " succeeded") 20 | MESSAGES = append(MESSAGES, NewMessage("GroupEnd", message)) 21 | 22 | if COLORS == true { 23 | os.Stdout.WriteString("\u001b[42m" + offset + "\\" + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 24 | } else { 25 | os.Stdout.WriteString(offset + "\\" + toSeparator(message) + message + "\n") 26 | } 27 | 28 | } else { 29 | 30 | message = strings.TrimSpace(message + " failed") 31 | MESSAGES = append(MESSAGES, NewMessage("GroupEnd", message)) 32 | 33 | if COLORS == true { 34 | os.Stdout.WriteString("\u001b[41m" + offset + "\\" + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 35 | } else { 36 | os.Stdout.WriteString(offset + "\\" + toSeparator(message) + message + "\n") 37 | } 38 | 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /toolchain/console/Info.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | import "strings" 5 | 6 | func Info(message string) { 7 | 8 | if features[FeatureInfo] == true { 9 | 10 | message = sanitize(message) 11 | offset := toOffset() 12 | MESSAGES = append(MESSAGES, NewMessage("Info", message)) 13 | 14 | if strings.Contains(message, "\n") { 15 | 16 | var lines = strings.Split(message, "\n") 17 | 18 | if COLORS == true { 19 | 20 | for l := 0; l < len(lines); l++ { 21 | os.Stdout.WriteString("\u001b[42m" + offset + toSeparator(lines[l]) + lines[l] + "\u001b[K\n") 22 | } 23 | 24 | os.Stdout.WriteString("\u001b[0m") 25 | 26 | } else { 27 | 28 | for l := 0; l < len(lines); l++ { 29 | os.Stdout.WriteString(offset + toSeparator(lines[l]) + lines[l] + "\n") 30 | } 31 | 32 | } 33 | 34 | } else { 35 | 36 | if COLORS == true { 37 | os.Stdout.WriteString("\u001b[42m" + offset + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 38 | } else { 39 | os.Stdout.WriteString(offset + toSeparator(message) + message + "\n") 40 | } 41 | 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /toolchain/console/Log.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | import "strings" 5 | 6 | func Log(message string) { 7 | 8 | if features[FeatureLog] == true { 9 | 10 | message = sanitize(message) 11 | offset := toOffset() 12 | MESSAGES = append(MESSAGES, NewMessage("Log", message)) 13 | 14 | if strings.Contains(message, "\n") { 15 | 16 | var lines = strings.Split(message, "\n") 17 | 18 | if COLORS == true { 19 | 20 | for l := 0; l < len(lines); l++ { 21 | os.Stdout.WriteString("\u001b[40m" + offset + toSeparator(lines[l]) + lines[l] + "\u001b[K\n") 22 | } 23 | 24 | os.Stdout.WriteString("\u001b[0m") 25 | 26 | } else { 27 | 28 | for l := 0; l < len(lines); l++ { 29 | os.Stdout.WriteString(offset + toSeparator(lines[l]) + lines[l] + "\n") 30 | } 31 | 32 | } 33 | 34 | } else { 35 | 36 | if COLORS == true { 37 | os.Stdout.WriteString("\u001b[40m" + offset + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 38 | } else { 39 | os.Stdout.WriteString(offset + toSeparator(message) + message + "\n") 40 | } 41 | 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /toolchain/console/Message.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | type Message struct { 4 | Method string `json:"type"` 5 | Value string `json:"value"` 6 | } 7 | 8 | func NewMessage(method string, value string) Message { 9 | 10 | var message Message 11 | 12 | message.Method = method 13 | message.Value = value 14 | 15 | return message 16 | 17 | } 18 | -------------------------------------------------------------------------------- /toolchain/console/Progress.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | import "strings" 5 | 6 | func Progress(message string) { 7 | 8 | if features[FeatureProgress] == true { 9 | 10 | message = strings.ReplaceAll(message, "\n", "") 11 | message = sanitize(message) 12 | offset := toOffset() 13 | 14 | if len(MESSAGES) > 0 { 15 | 16 | last_method := MESSAGES[len(MESSAGES)-1].Method 17 | 18 | if last_method == "Progress" { 19 | os.Stdout.WriteString("\033[A\033[2K\r") 20 | MESSAGES[len(MESSAGES)-1] = NewMessage("Progress", message) 21 | } else { 22 | MESSAGES = append(MESSAGES, NewMessage("Progress", message)) 23 | } 24 | 25 | } else { 26 | MESSAGES = append(MESSAGES, NewMessage("Progress", message)) 27 | } 28 | 29 | if COLORS == true { 30 | os.Stdout.WriteString("\u001b[40m" + offset + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 31 | } else { 32 | os.Stdout.WriteString(offset + toSeparator(message) + message + "\n") 33 | } 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /toolchain/console/Result.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | func Result(result bool, message string) { 4 | 5 | if result == true { 6 | Info(message) 7 | } else { 8 | Error(message) 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /toolchain/console/Warn.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | import "strings" 5 | 6 | func Warn(message string) { 7 | 8 | if features[FeatureWarn] == true { 9 | 10 | message = sanitize(message) 11 | offset := toOffset() 12 | MESSAGES = append(MESSAGES, NewMessage("Warn", message)) 13 | 14 | if strings.Contains(message, "\n") { 15 | 16 | var lines = strings.Split(message, "\n") 17 | 18 | if COLORS == true { 19 | 20 | for l := 0; l < len(lines); l++ { 21 | os.Stdout.WriteString("\u001b[43m" + offset + toSeparator(lines[l]) + lines[l] + "\u001b[K\n") 22 | } 23 | 24 | os.Stdout.WriteString("\u001b[0m") 25 | 26 | } else { 27 | 28 | for l := 0; l < len(lines); l++ { 29 | os.Stdout.WriteString(offset + toSeparator(lines[l]) + lines[l] + "\n") 30 | } 31 | 32 | } 33 | 34 | } else { 35 | 36 | if COLORS == true { 37 | os.Stdout.WriteString("\u001b[43m" + offset + toSeparator(message) + message + "\u001b[K\u001b[0m\n") 38 | } else { 39 | os.Stdout.WriteString(offset + toSeparator(message) + message + "\n") 40 | } 41 | 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /toolchain/console/console.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | import "os" 4 | import "strings" 5 | 6 | var COLORS bool = true 7 | var MESSAGES []Message 8 | var OFFSET int = 0 9 | 10 | func init() { 11 | 12 | MESSAGES = make([]Message, 0) 13 | 14 | term := strings.ToLower(os.Getenv("TERM")) 15 | 16 | if term == "xterm" { 17 | COLORS = false 18 | } else if term == "xterm-16color" { 19 | COLORS = false 20 | } else if term == "xterm-88color" { 21 | COLORS = true 22 | } else if term == "xterm-256color" { 23 | COLORS = true 24 | } else if term == "xterm-kitty" { 25 | COLORS = true 26 | } 27 | 28 | no_color := strings.ToLower(os.Getenv("NO_COLOR")) 29 | 30 | if no_color != "" { 31 | 32 | if no_color == "yes" || no_color == "true" || no_color == "1" { 33 | COLORS = false 34 | } 35 | 36 | } 37 | 38 | } 39 | 40 | func sanitize(message string) string { 41 | 42 | var result string = message 43 | 44 | result = strings.ReplaceAll(result, "\t", " ") 45 | 46 | return result 47 | 48 | } 49 | 50 | func toOffset() string { 51 | 52 | var offset string 53 | 54 | if OFFSET > 0 { 55 | 56 | offset = "|" 57 | 58 | for o := 1; o < OFFSET; o++ { 59 | offset += "|" 60 | } 61 | 62 | } 63 | 64 | return offset 65 | 66 | } 67 | 68 | func toSeparator(message string) string { 69 | 70 | var separator string 71 | 72 | if strings.HasPrefix(message, ">") { 73 | separator = "-" 74 | } else if strings.HasPrefix(message, "-") { 75 | separator = "-" 76 | } else { 77 | separator = " " 78 | } 79 | 80 | return separator 81 | 82 | } 83 | -------------------------------------------------------------------------------- /toolchain/console/features.go: -------------------------------------------------------------------------------- 1 | package console 2 | 3 | const ( 4 | FeatureAll = 0 5 | FeatureGroup = 1 6 | FeatureLog = 2 7 | FeatureInfo = 3 8 | FeatureWarn = 4 9 | FeatureError = 5 10 | FeatureInspect = 6 11 | FeatureProgress = 7 12 | ) 13 | 14 | var features map[int]bool 15 | 16 | func init() { 17 | 18 | features = make(map[int]bool) 19 | 20 | features[FeatureGroup] = true 21 | features[FeatureLog] = true 22 | features[FeatureInfo] = true 23 | features[FeatureWarn] = true 24 | features[FeatureError] = true 25 | features[FeatureInspect] = true 26 | features[FeatureProgress] = true 27 | 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /toolchain/cvs/Decrypt.go: -------------------------------------------------------------------------------- 1 | package cvs 2 | 3 | import "cookie.engineer/console" 4 | import "crypto/aes" 5 | import "crypto/cipher" 6 | import "encoding/hex" 7 | import "strconv" 8 | 9 | func Decrypt(buffer []byte, password string) []byte { 10 | 11 | var result []byte 12 | 13 | console.Group("cvs/Decrypt") 14 | 15 | salt := buffer[0:16] 16 | iv := buffer[16:16+12] 17 | data := buffer[16+12:] 18 | key := DeriveKey(password, salt) 19 | 20 | console.Log("Salt: " + hex.EncodeToString(salt)) 21 | console.Log("IV: " + hex.EncodeToString(iv)) 22 | console.Log("Key: " + hex.EncodeToString(key)) 23 | console.Log("Input Buffer: " + strconv.Itoa(len(data)) + " bytes") 24 | 25 | block, err0 := aes.NewCipher(key) 26 | 27 | if err0 == nil { 28 | 29 | aes_gcm, err1 := cipher.NewGCM(block) 30 | 31 | if err1 == nil { 32 | 33 | tmp, err2 := aes_gcm.Open(nil, iv, data, nil) 34 | 35 | if err2 == nil { 36 | console.Log("Output Buffer: " + strconv.Itoa(len(tmp)) + " bytes") 37 | result = tmp 38 | } 39 | 40 | } 41 | 42 | } 43 | 44 | console.GroupEnd("cvs/Decrypt") 45 | 46 | return result 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /toolchain/cvs/DeriveFilename.go: -------------------------------------------------------------------------------- 1 | package cvs 2 | 3 | import "encoding/hex" 4 | import "crypto/sha256" 5 | 6 | func DeriveFilename(password string) string { 7 | 8 | hasher := sha256.New() 9 | hasher.Write([]byte(password)) 10 | bytes := hasher.Sum(nil) 11 | 12 | return hex.EncodeToString(bytes) + ".cv" 13 | 14 | } 15 | -------------------------------------------------------------------------------- /toolchain/cvs/DeriveKey.go: -------------------------------------------------------------------------------- 1 | package cvs 2 | 3 | import "golang.org/x/crypto/pbkdf2" 4 | import "crypto/sha256" 5 | 6 | func DeriveKey(password string, salt []byte) []byte { 7 | return pbkdf2.Key([]byte(password), salt, 250000, 32, sha256.New) 8 | } 9 | -------------------------------------------------------------------------------- /toolchain/cvs/Encrypt.go: -------------------------------------------------------------------------------- 1 | package cvs 2 | 3 | import "cookie.engineer/console" 4 | import "crypto/aes" 5 | import "crypto/cipher" 6 | import "crypto/rand" 7 | import "encoding/hex" 8 | import "strconv" 9 | 10 | func Encrypt(buffer []byte, password string) []byte { 11 | 12 | var result []byte 13 | 14 | console.Group("cvs/Encrypt") 15 | 16 | salt := make([]byte, 16) 17 | rand.Read(salt) 18 | 19 | iv := make([]byte, 12) 20 | rand.Read(iv) 21 | 22 | key := DeriveKey(password, salt) 23 | 24 | console.Log("Salt: " + hex.EncodeToString(salt)) 25 | console.Log("IV: " + hex.EncodeToString(iv)) 26 | console.Log("Key: " + hex.EncodeToString(key)) 27 | console.Log("Input Buffer: " + strconv.Itoa(len(buffer)) + " bytes") 28 | 29 | block, err0 := aes.NewCipher(key) 30 | 31 | if err0 == nil { 32 | 33 | aes_gcm, err1 := cipher.NewGCM(block) 34 | 35 | if err1 == nil { 36 | 37 | tmp := aes_gcm.Seal(nil, iv, buffer, nil) 38 | 39 | console.Log("Output Buffer: " + strconv.Itoa(len(tmp)) + " bytes") 40 | 41 | result = append(result, salt...) 42 | result = append(result, iv...) 43 | result = append(result, tmp...) 44 | 45 | } 46 | 47 | } 48 | 49 | console.GroupEnd("cvs/Encrypt") 50 | 51 | return result 52 | 53 | } 54 | -------------------------------------------------------------------------------- /toolchain/cvs/cvs_test.go: -------------------------------------------------------------------------------- 1 | package cvs 2 | 3 | import "testing" 4 | 5 | func TestEncryptDecrypt(t *testing.T) { 6 | 7 | t.Run("self-check", func(t *testing.T) { 8 | 9 | buffer := []byte("Hello, World!") 10 | password := "password123" 11 | 12 | encrypted := Encrypt(buffer, password) 13 | decrypted := Decrypt(encrypted, password) 14 | 15 | if string(buffer) != string(decrypted) { 16 | t.Errorf("Expected '%s' but got '%s'", buffer, decrypted) 17 | } 18 | 19 | }) 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /toolchain/go.mod: -------------------------------------------------------------------------------- 1 | module cookie.engineer 2 | 3 | go 1.22 4 | 5 | require golang.org/x/crypto v0.27.0 // indirect 6 | -------------------------------------------------------------------------------- /toolchain/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= 2 | golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= 3 | -------------------------------------------------------------------------------- /toolchain/routes/ModifyFile.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "cookie.engineer/utils" 4 | import "net/http" 5 | import "io" 6 | import "os" 7 | 8 | func ModifyFile(root string, file string, response http.ResponseWriter, request *http.Request) { 9 | 10 | if request.Method == http.MethodPost { 11 | 12 | buffer, err1 := io.ReadAll(request.Body) 13 | result := false 14 | 15 | if err1 == nil { 16 | 17 | err2 := os.WriteFile(root + "/" + file, buffer, 0666) 18 | 19 | if err2 == nil { 20 | result = true 21 | } 22 | 23 | } 24 | 25 | if result == true { 26 | utils.RespondWith(response, file, http.StatusOK) 27 | } else { 28 | utils.RespondWith(response, file, http.StatusForbidden) 29 | } 30 | 31 | } else { 32 | utils.RespondWith(response, file, http.StatusMethodNotAllowed) 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /toolchain/routes/RemoveFile.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "cookie.engineer/utils" 4 | import "fmt" 5 | import "net/http" 6 | 7 | func RemoveFile(root string, file string, response http.ResponseWriter, request *http.Request) { 8 | 9 | if request.Method == http.MethodDelete { 10 | 11 | fmt.Println("TODO: Remove file " + file) 12 | // TODO 13 | 14 | } else { 15 | utils.RespondWith(response, file, http.StatusMethodNotAllowed) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /toolchain/routes/RenderArticle.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "cookie.engineer/console" 4 | import "cookie.engineer/structs" 5 | import "cookie.engineer/templates" 6 | import "bytes" 7 | import "os" 8 | import "strings" 9 | 10 | func RenderArticle(root string, file string) bool { 11 | 12 | var result bool = false 13 | 14 | name := "" 15 | 16 | if strings.HasSuffix(file, ".html") { 17 | name = file[0:len(file)-5] 18 | } else if strings.HasSuffix(file, ".md") { 19 | name = file[0:len(file)-3] 20 | } 21 | 22 | if name != "" { 23 | 24 | buffer, err1 := os.ReadFile(root + "/weblog/articles/"+name+".md") 25 | 26 | if err1 == nil { 27 | 28 | document := structs.NewDocument(name+".md", string(buffer)) 29 | 30 | var buffer bytes.Buffer 31 | 32 | if templates.Article != nil { 33 | 34 | err2 := templates.Article.Execute(&buffer, document) 35 | 36 | if err2 == nil { 37 | 38 | err3 := os.WriteFile(root+"/weblog/articles/"+name+".html", buffer.Bytes(), 0666) 39 | 40 | if err3 == nil { 41 | result = true 42 | } 43 | 44 | } else { 45 | console.Warn("File \"" + name + ".md\" cannot be parsed") 46 | } 47 | 48 | } 49 | 50 | } else { 51 | console.Warn("File \"" + name + ".md\" does not exist") 52 | } 53 | 54 | } 55 | 56 | if result == true { 57 | console.Info("Rendered \"" + name + ".md\"") 58 | } else { 59 | console.Error("Cannot render \"" + name + ".md\"") 60 | } 61 | 62 | return result 63 | 64 | } 65 | -------------------------------------------------------------------------------- /toolchain/routes/RenderArticles.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "os" 4 | import "strings" 5 | 6 | func RenderArticles(root string) { 7 | 8 | entries, err1 := os.ReadDir(root + "/weblog/articles") 9 | 10 | if err1 == nil { 11 | 12 | for _, entry := range entries { 13 | 14 | name := entry.Name() 15 | 16 | if strings.HasSuffix(name, ".md") { 17 | RenderArticle(root, name) 18 | } 19 | 20 | } 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /toolchain/routes/RenderFeed.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "cookie.engineer/structs" 4 | import "cookie.engineer/templates" 5 | import "bytes" 6 | import "os" 7 | import "strings" 8 | 9 | func RenderFeed(root string) bool { 10 | 11 | var result bool = false 12 | 13 | entries, err1 := os.ReadDir(root + "/weblog/articles") 14 | 15 | feed := structs.NewFeed() 16 | 17 | if err1 == nil { 18 | 19 | for _, entry := range entries { 20 | 21 | name := entry.Name() 22 | 23 | if strings.HasSuffix(name, ".md") { 24 | 25 | buffer, err2 := os.ReadFile(root + "/weblog/articles/"+name) 26 | 27 | if err2 == nil { 28 | 29 | document := structs.NewDocument(name[0:len(name)-3]+".html", string(buffer)) 30 | 31 | if document.IsValid() { 32 | feed.AddDocument(document) 33 | } 34 | 35 | } 36 | 37 | } 38 | 39 | } 40 | 41 | } 42 | 43 | feed.Sort() 44 | 45 | var buffer bytes.Buffer 46 | 47 | if templates.Feed != nil { 48 | 49 | err2 := templates.Feed.Execute(&buffer, feed) 50 | 51 | if err2 == nil { 52 | 53 | err3 := os.WriteFile(root + "/weblog/feed.xml", buffer.Bytes(), 0666) 54 | 55 | if err3 == nil { 56 | result = true 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | return result 64 | 65 | } 66 | -------------------------------------------------------------------------------- /toolchain/routes/RenderIndex.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "cookie.engineer/structs" 4 | import "cookie.engineer/templates" 5 | import "bytes" 6 | import "os" 7 | import "strings" 8 | 9 | func RenderIndex(root string) bool { 10 | 11 | var result bool = false 12 | 13 | entries, err1 := os.ReadDir(root + "/weblog/articles") 14 | 15 | index := structs.NewIndex() 16 | 17 | if err1 == nil { 18 | 19 | for _, entry := range entries { 20 | 21 | name := entry.Name() 22 | 23 | if strings.HasSuffix(name, ".md") { 24 | 25 | buffer, err2 := os.ReadFile(root + "/weblog/articles/"+name) 26 | 27 | if err2 == nil { 28 | 29 | document := structs.NewDocument(name[0:len(name)-3]+".html", string(buffer)) 30 | 31 | if document.IsValid() { 32 | index.AddDocument(document) 33 | } 34 | 35 | } 36 | 37 | } 38 | 39 | } 40 | 41 | } 42 | 43 | index.Sort() 44 | 45 | var buffer bytes.Buffer 46 | 47 | if templates.Index != nil { 48 | 49 | err2 := templates.Index.Execute(&buffer, index) 50 | 51 | if err2 == nil { 52 | 53 | err3 := os.WriteFile(root + "/weblog/index.html", buffer.Bytes(), 0666) 54 | 55 | if err3 == nil { 56 | result = true 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | return result 64 | 65 | } 66 | -------------------------------------------------------------------------------- /toolchain/routes/ServeArticle.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "net/http" 4 | import "strings" 5 | 6 | func ServeArticle(root string, response http.ResponseWriter, request *http.Request) { 7 | 8 | file := request.PathValue("file") 9 | 10 | if strings.HasSuffix(file, ".html") { 11 | 12 | result := RenderArticle(root, file) 13 | 14 | if result == true { 15 | 16 | ServeFile(root+"/weblog/articles", file, response, request) 17 | 18 | } else { 19 | 20 | response.Header().Set("Content-Type", "text/html") 21 | response.WriteHeader(http.StatusInternalServerError) 22 | response.Write([]byte("Syntax Error in Markdown Document")) 23 | 24 | } 25 | 26 | } else if strings.HasSuffix(file, ".md") { 27 | ServeFile(root+"/weblog/articles", file, response, request) 28 | } else { 29 | ServeFile(root+"/weblog/articles", file, response, request) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /toolchain/routes/ServeArticleIndex.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "encoding/json" 4 | import "net/http" 5 | import "os" 6 | import "strconv" 7 | import "strings" 8 | 9 | func ServeArticleIndex(root string, response http.ResponseWriter, request *http.Request) { 10 | 11 | if request.Method == http.MethodGet { 12 | 13 | entries, err1 := os.ReadDir(root + "/weblog/articles") 14 | 15 | if err1 == nil { 16 | 17 | var result []string 18 | 19 | for _, entry := range entries { 20 | 21 | name := entry.Name() 22 | 23 | if strings.HasSuffix(name, ".md") { 24 | result = append(result, name) 25 | } 26 | 27 | } 28 | 29 | buffer, err2 := json.MarshalIndent(result, "", "\t") 30 | 31 | if err2 == nil { 32 | 33 | response.Header().Set("Content-Type", "application/json") 34 | response.Header().Set("Content-Length", strconv.Itoa(len(buffer))) 35 | response.WriteHeader(http.StatusOK) 36 | response.Write(buffer) 37 | 38 | } else { 39 | 40 | response.Header().Set("Content-Type", "application/json") 41 | response.WriteHeader(http.StatusInternalServerError) 42 | response.Write([]byte{}) 43 | 44 | } 45 | 46 | } else { 47 | 48 | response.Header().Set("Content-Type", "application/json") 49 | response.WriteHeader(http.StatusNotFound) 50 | response.Write([]byte{}) 51 | 52 | } 53 | 54 | } else { 55 | 56 | response.Header().Set("Content-Type", "application/json") 57 | response.WriteHeader(http.StatusMethodNotAllowed) 58 | response.Write([]byte{}) 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /toolchain/routes/ServeFile.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import "cookie.engineer/utils" 4 | import "net/http" 5 | import "os" 6 | import "strconv" 7 | import "strings" 8 | 9 | func ServeFile(root string, file string, response http.ResponseWriter, request *http.Request) { 10 | 11 | if request.Method == http.MethodGet { 12 | 13 | extension := file[strings.LastIndex(file, ".")+1:] 14 | buffer, err1 := os.ReadFile(root + "/" + file) 15 | 16 | if err1 == nil { 17 | 18 | content_type, ok := utils.MIME[extension] 19 | 20 | if ok == false { 21 | content_type = "application/octet-stream" 22 | } 23 | 24 | response.Header().Set("Content-Type", content_type) 25 | response.Header().Set("Content-Length", strconv.Itoa(len(buffer))) 26 | response.WriteHeader(http.StatusOK) 27 | response.Write(buffer) 28 | 29 | } else { 30 | utils.RespondWith(response, file, http.StatusNotFound) 31 | } 32 | 33 | } else { 34 | utils.RespondWith(response, file, http.StatusMethodNotAllowed) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /toolchain/structs/Emojis.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | var Emojis map[string]string = map[string]string{ 4 | "balloon": "🎈", 5 | "blue_book": "📘", 6 | "bomb": "💣", 7 | "book": "🕮", 8 | "bug": "🐛", 9 | "calendar": "📆", 10 | "castle": "🌍", 11 | "china": "🇨🇳", 12 | "compass": "🧭", 13 | "computer": "🖥️", 14 | "construction": "🚧", 15 | "cyclone": "🌀", 16 | "date": "📅", 17 | "eu": "🇪🇺", 18 | "gear": "⚙️", 19 | "ghost": "👻", 20 | "gift": "🎁", 21 | "globe": "🌍", 22 | "green_book": "📗", 23 | "joystick": "🕹️", 24 | "laptop": "💻", 25 | "mag": "🔍", 26 | "magnet": "🧲", 27 | "notebook": "📓", 28 | "orange_book": "📙", 29 | "pushpin": "📌", 30 | "rainbow": "🌈", 31 | "robot": "🤖", 32 | "rocket": "🚀", 33 | "russia": "🇷🇺", 34 | "satellite": "📡", 35 | "shit": "💩", 36 | "sparkles": "✨", 37 | "snowflake": "❄️", 38 | "tornado": "🌪️", 39 | "us": "🇺🇸", 40 | "zap": "⚡", 41 | } 42 | -------------------------------------------------------------------------------- /toolchain/structs/Feed.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import "sort" 4 | import "time" 5 | 6 | type Feed struct { 7 | Date string `json:"date"` 8 | Documents []*Document `json:"documents"` 9 | } 10 | 11 | func NewFeed() Feed { 12 | 13 | var feed Feed 14 | 15 | feed.Date = "Sat, 01 Jan 2000 00:00:00 UTC" 16 | feed.Documents = make([]*Document, 0) 17 | 18 | return feed 19 | 20 | } 21 | 22 | func (feed *Feed) AddDocument(value Document) { 23 | 24 | var document = &value 25 | 26 | if document.IsValid() { 27 | 28 | if document.Meta.Date != "" { 29 | 30 | date, _ := time.Parse(time.DateOnly, document.Meta.Date) 31 | feed_date, _ := time.Parse(time.RFC1123, feed.Date) 32 | 33 | if date.After(feed_date) { 34 | feed.Date = date.Format(time.RFC1123) 35 | } 36 | 37 | document.Meta.Date = date.Format(time.RFC1123) 38 | 39 | } 40 | 41 | feed.Documents = append(feed.Documents, document) 42 | 43 | } 44 | 45 | } 46 | 47 | func (feed *Feed) Sort() { 48 | 49 | sort.Slice(feed.Documents, func(a int, b int) bool { 50 | 51 | date_a, _ := time.Parse(time.RFC1123, feed.Documents[a].Meta.Date) 52 | date_b, _ := time.Parse(time.RFC1123, feed.Documents[b].Meta.Date) 53 | 54 | return date_a.After(date_b) 55 | 56 | }) 57 | 58 | } 59 | -------------------------------------------------------------------------------- /toolchain/structs/Index.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import "sort" 4 | import "time" 5 | 6 | type Index struct { 7 | Documents []*Document `json:"documents"` 8 | } 9 | 10 | func NewIndex() Index { 11 | 12 | var index Index 13 | 14 | index.Documents = make([]*Document, 0) 15 | 16 | return index 17 | 18 | } 19 | 20 | func (index *Index) AddDocument(value Document) { 21 | 22 | var document = &value 23 | 24 | if document.IsValid() { 25 | document.Count() 26 | index.Documents = append(index.Documents, document) 27 | } 28 | 29 | } 30 | 31 | func (index *Index) Sort() { 32 | 33 | sort.Slice(index.Documents, func(a int, b int) bool { 34 | 35 | date_a, _ := time.Parse(time.DateOnly, index.Documents[a].Meta.Date) 36 | date_b, _ := time.Parse(time.DateOnly, index.Documents[b].Meta.Date) 37 | 38 | return date_a.After(date_b) 39 | 40 | }) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /toolchain/structs/countWords.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import "strings" 4 | 5 | func countWords(element *Element) int { 6 | 7 | var result int = 0 8 | 9 | if element.Text != "" { 10 | 11 | words := strings.Split(element.Text, " ") 12 | 13 | for w := 0; w < len(words); w++ { 14 | result++ 15 | } 16 | 17 | } 18 | 19 | if len(element.Children) > 0 { 20 | 21 | for c := 0; c < len(element.Children); c++ { 22 | result += countWords(element.Children[c]) 23 | } 24 | 25 | } 26 | 27 | return result 28 | 29 | } 30 | -------------------------------------------------------------------------------- /toolchain/structs/generateId.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import "cookie.engineer/utils" 4 | import "strings" 5 | 6 | func generateId(element *Element) string { 7 | 8 | var texts []string 9 | 10 | if element.Text != "" { 11 | 12 | chunks := strings.Split(strings.TrimSpace(utils.ToASCII(element.Text)), "-") 13 | 14 | for c := 0; c < len(chunks); c++ { 15 | 16 | text := strings.TrimSpace(chunks[c]) 17 | 18 | if len(text) > 0 { 19 | texts = append(texts, text) 20 | } 21 | 22 | } 23 | 24 | } else if len(element.Children) > 0 { 25 | 26 | for c := 0; c < len(element.Children); c++ { 27 | 28 | child := element.Children[c] 29 | 30 | if child.Type == "b" || child.Type == "code" || child.Type == "del" || child.Type == "em" || child.Type == "#text" { 31 | 32 | tmp := strings.TrimSpace(utils.ToASCIIName(child.Text)) 33 | 34 | if strings.HasPrefix(tmp, "-") { 35 | tmp = tmp[1:] 36 | } 37 | 38 | if strings.HasSuffix(tmp, "-") { 39 | tmp = tmp[0 : len(tmp)-1] 40 | } 41 | 42 | chunks := strings.Split(tmp, "-") 43 | 44 | for c := 0; c < len(chunks); c++ { 45 | 46 | text := strings.TrimSpace(chunks[c]) 47 | 48 | if len(text) > 0 { 49 | texts = append(texts, text) 50 | } 51 | 52 | } 53 | 54 | } 55 | 56 | } 57 | 58 | } 59 | 60 | var filtered []string 61 | 62 | if len(texts) > 0 { 63 | 64 | if utils.IsNumber(string(texts[0][0])) { 65 | texts = texts[1:] 66 | } 67 | 68 | for t := 0; t < len(texts); t++ { 69 | 70 | text := strings.ToLower(strings.TrimSpace(texts[t])) 71 | 72 | if text != "" { 73 | filtered = append(filtered, text) 74 | } 75 | 76 | } 77 | 78 | return strings.Join(filtered, "-") 79 | 80 | } 81 | 82 | return "" 83 | 84 | } 85 | -------------------------------------------------------------------------------- /toolchain/templates/Article.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import _ "embed" 4 | import "text/template" 5 | 6 | var Article *template.Template 7 | 8 | //go:embed Article.tpl 9 | var embedded_Article []byte 10 | 11 | func init() { 12 | 13 | tpl, err := template.New("Article").Funcs(template.FuncMap{ 14 | "RenderElement": RenderElement, 15 | "RenderElements": RenderElements, 16 | "RenderInteger": RenderInteger, 17 | "RenderStrings": RenderStrings, 18 | }).Parse(string(embedded_Article)) 19 | 20 | if err == nil { 21 | Article = tpl 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /toolchain/templates/Feed.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import _ "embed" 4 | import "text/template" 5 | 6 | var Feed *template.Template 7 | 8 | //go:embed Feed.tpl 9 | var embedded_Feed []byte 10 | 11 | func init() { 12 | 13 | tpl, err := template.New("Feed").Funcs(template.FuncMap{ 14 | "RenderElement": RenderElement, 15 | "RenderElements": RenderElements, 16 | "RenderInteger": RenderInteger, 17 | "RenderStrings": RenderStrings, 18 | }).Parse(string(embedded_Feed)) 19 | 20 | if err == nil { 21 | Feed = tpl 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /toolchain/templates/Feed.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Cookie Engineer's Web Log 5 | Web Log about Software Architecture and Automation 6 | Computers/Software/Internet/Automation/Robotics/Artificial Intelligence/Machine Learning 7 | Copyright 2019-2024 Cookie Engineer 8 | en-us 9 | {{.Date}} 10 | @cookiengineer 11 | {{.Date}} 12 | 13 | https://cookie.engineer/design/cookiengineer.png 14 | Cookie Engineer's Web Log 15 | https://cookie.engineer/weblog/index.html 16 | Web Log about Software Architecture and Automation 17 | 256 18 | 256 19 | {{range .Documents}} 20 | 21 | {{.Meta.Name}} 22 | {{.Meta.Crux}} 23 | https://cookie.engineer/weblog/articles/{{.File}} 24 | {{RenderStrings .Meta.Tags "/"}} 25 | {{.Meta.Date}} 26 | {{end}} 27 | 28 | 29 | -------------------------------------------------------------------------------- /toolchain/templates/Index.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import _ "embed" 4 | import "text/template" 5 | 6 | var Index *template.Template 7 | 8 | //go:embed Index.tpl 9 | var embedded_Index []byte 10 | 11 | func init() { 12 | 13 | tpl, err := template.New("Index").Funcs(template.FuncMap{ 14 | "RenderElement": RenderElement, 15 | "RenderElements": RenderElements, 16 | "RenderInteger": RenderInteger, 17 | "RenderStrings": RenderStrings, 18 | }).Parse(string(embedded_Index)) 19 | 20 | if err == nil { 21 | Index = tpl 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /toolchain/templates/RenderElement.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import "cookie.engineer/structs" 4 | 5 | func RenderElement(element structs.Element, indent string) string { 6 | return element.Render(indent) 7 | } 8 | -------------------------------------------------------------------------------- /toolchain/templates/RenderElements.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import "cookie.engineer/structs" 4 | 5 | func RenderElements(elements []*structs.Element, indent string) string { 6 | 7 | var result string 8 | 9 | for e := 0; e < len(elements); e++ { 10 | 11 | tmp := elements[e].Render(indent) 12 | 13 | if e == 0 { 14 | result += tmp 15 | } else { 16 | result += " " + tmp 17 | } 18 | 19 | } 20 | 21 | return result 22 | 23 | } 24 | -------------------------------------------------------------------------------- /toolchain/templates/RenderInteger.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import "strconv" 4 | 5 | func RenderInteger(number int) string { 6 | return strconv.Itoa(number) 7 | } 8 | -------------------------------------------------------------------------------- /toolchain/templates/RenderStrings.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import "strings" 4 | 5 | func RenderStrings(slice []string, separator string) string { 6 | return strings.Join(slice, separator) 7 | } 8 | -------------------------------------------------------------------------------- /toolchain/utils/IsNumber.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func IsNumber(value string) bool { 4 | 5 | var result bool = true 6 | 7 | for v := 0; v < len(value); v++ { 8 | 9 | character := string(value[v]) 10 | 11 | if character >= "0" && character <= "9" { 12 | continue 13 | } else { 14 | result = false 15 | break 16 | } 17 | 18 | } 19 | 20 | return result 21 | 22 | } 23 | -------------------------------------------------------------------------------- /toolchain/utils/RespondWith.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "net/http" 4 | import "strings" 5 | 6 | func RespondWith(response http.ResponseWriter, file string, status int) { 7 | 8 | extension := file[strings.LastIndex(file, ".")+1:] 9 | content_type, ok := MIME[extension] 10 | 11 | if ok == false { 12 | content_type = "application/octet-stream" 13 | } 14 | 15 | response.Header().Set("Content-Type", content_type) 16 | response.WriteHeader(status) 17 | response.Write([]byte{}) 18 | 19 | } 20 | -------------------------------------------------------------------------------- /toolchain/utils/ToASCII.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "encoding/json" 4 | import _ "embed" 5 | import "strings" 6 | 7 | //go:embed ToASCII.UTF8.json 8 | var embedded_utf8_table []byte 9 | 10 | var utf8_table map[string][]uint16 11 | 12 | func init() { 13 | json.Unmarshal(embedded_utf8_table, &utf8_table) 14 | } 15 | 16 | func lookup(character uint16) string { 17 | 18 | var found string 19 | 20 | for str, codes := range utf8_table { 21 | 22 | for c := 0; c < len(codes); c++ { 23 | 24 | if codes[c] == character { 25 | found = str 26 | break 27 | } 28 | 29 | } 30 | 31 | } 32 | 33 | return found 34 | 35 | } 36 | 37 | func ToASCII(value string) string { 38 | 39 | tmp := strings.TrimSpace(value) 40 | 41 | var filtered string 42 | 43 | for _, character := range tmp { 44 | 45 | var mapped = lookup(uint16(character)) 46 | 47 | if mapped != "" { 48 | filtered += mapped 49 | } 50 | 51 | } 52 | 53 | return filtered 54 | 55 | } 56 | -------------------------------------------------------------------------------- /toolchain/utils/ToASCIIName.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "strings" 4 | 5 | func ToASCIIName(value string) string { 6 | 7 | tmp := ToASCII(value) 8 | 9 | var filtered string 10 | var last_was_dash bool = false 11 | 12 | for _, chunk := range tmp { 13 | 14 | if chunk == 32 || chunk == 45 || chunk == 58 || chunk == 59 || chunk == 95 { 15 | 16 | if last_was_dash == false { 17 | filtered += "-" 18 | last_was_dash = true 19 | } 20 | 21 | } else if chunk >= 33 && chunk <= 47 { 22 | 23 | // Do Nothing 24 | 25 | } else if chunk >= 48 && chunk <= 57 { 26 | 27 | // Digits 28 | filtered += string(chunk) 29 | last_was_dash = false 30 | 31 | } else if chunk >= 58 && chunk <= 64 { 32 | 33 | // Do Nothing 34 | 35 | } else if chunk >= 65 && chunk <= 90 { 36 | 37 | // Uppercase letters 38 | filtered += string(chunk) 39 | last_was_dash = false 40 | 41 | } else if chunk >= 91 && chunk <= 96 { 42 | 43 | // Do Nothing 44 | 45 | } else if chunk >= 97 && chunk <= 122 { 46 | 47 | // Lowercase letters 48 | filtered += string(chunk) 49 | last_was_dash = false 50 | 51 | } else if chunk >= 123 && chunk <= 126 { 52 | 53 | // Do Nothing 54 | 55 | } 56 | 57 | } 58 | 59 | if filtered != "-" { 60 | filtered = strings.TrimSpace(filtered) 61 | } 62 | 63 | return filtered 64 | 65 | } 66 | -------------------------------------------------------------------------------- /weblog/articles/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": false, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "parserOptions": { 9 | "ecmaVersion": 2018, 10 | "sourceType": "module" 11 | }, 12 | "overrides": [{ 13 | "files": [ "*.mjs" ], 14 | "rules": {} 15 | }, { 16 | "files": [ "your-definition-of-privacy-is-wrong/prefs.js" ], 17 | "rules": { 18 | "no-undef": "off", 19 | "quotes": "off" 20 | } 21 | }], 22 | "rules": { 23 | "no-restricted-globals": [ 24 | "error", 25 | { "name": "__dirname" }, 26 | { "name": "__filename" }, 27 | { "name": "Buffer" }, 28 | { "name": "exports" }, 29 | { "name": "module" }, 30 | { "name": "process" }, 31 | { "name": "require" }, 32 | { "name": "TextDecoder" }, 33 | { "name": "TextEncoder" }, 34 | { "name": "URL" }, 35 | { "name": "URLSearchParams" } 36 | ], 37 | "arrow-parens": [ 38 | "error", 39 | "always" 40 | ], 41 | "indent": [ 42 | "error", 43 | "tab" 44 | ], 45 | "linebreak-style": [ 46 | "error", 47 | "unix" 48 | ], 49 | "quotes": [ 50 | "error", 51 | "single" 52 | ], 53 | "semi": [ 54 | "error", 55 | "always" 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /weblog/articles/android-privacy-guide/appwarden.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/android-privacy-guide/appwarden.jpg -------------------------------------------------------------------------------- /weblog/articles/android-privacy-guide/osmand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/android-privacy-guide/osmand.jpg -------------------------------------------------------------------------------- /weblog/articles/android-privacy-guide/permission-manager-x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/android-privacy-guide/permission-manager-x.jpg -------------------------------------------------------------------------------- /weblog/articles/android-privacy-guide/rethinkdns.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/android-privacy-guide/rethinkdns.jpg -------------------------------------------------------------------------------- /weblog/articles/android-privacy-guide/superfreezz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/android-privacy-guide/superfreezz.jpg -------------------------------------------------------------------------------- /weblog/articles/dji-drone-reset-guide/dji-spark-with-controller.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/dji-drone-reset-guide/dji-spark-with-controller.jpg -------------------------------------------------------------------------------- /weblog/articles/gameboy-advance/gba-01-teardown.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/gameboy-advance/gba-01-teardown.jpg -------------------------------------------------------------------------------- /weblog/articles/gameboy-advance/gba-02-cleanup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/gameboy-advance/gba-02-cleanup.jpg -------------------------------------------------------------------------------- /weblog/articles/gameboy-advance/gba-03-displaymod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/gameboy-advance/gba-03-displaymod.jpg -------------------------------------------------------------------------------- /weblog/articles/gameboy-advance/gba-04-ezflash-omega.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/gameboy-advance/gba-04-ezflash-omega.jpg -------------------------------------------------------------------------------- /weblog/articles/i3-migration-guide/lxappearance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/i3-migration-guide/lxappearance.png -------------------------------------------------------------------------------- /weblog/articles/implementers-guide-to-socks/client-manual.mjs: -------------------------------------------------------------------------------- 1 | 2 | // client-manual.mjs 3 | import net from 'net'; 4 | 5 | 6 | 7 | const HANDSHAKE_REQUEST = [ 8 | 0x05, // SOCKS version 9 | 0x02, // 2 Auth Methods are supported 10 | 0x00, // methods[0]: No Authentication Required 11 | 0x02 // methods[1]: Username/Password 12 | ]; 13 | 14 | const CONNECTION_REQUEST = [ 15 | 16 | 0x05, // SOCKS version 17 | 0x01, // CONNECT Command 18 | 0x00, // Reserved (due to SOCKS4 compatibility) 19 | 0x01, // IPv4 Address Type 20 | 21 | 0x01, // 1.3.3.7 22 | 0x03, 23 | 0x03, 24 | 0x07, 25 | 26 | 80 // HTTP 27 | 28 | ]; 29 | 30 | 31 | let client = net.createConnection({ 32 | host: '127.0.0.1', 33 | port: 1080 34 | }, () => { 35 | 36 | client.once('data', (response) => { 37 | 38 | console.log('Handshake Response Frame', response); 39 | 40 | if (response[0] === 0x05 && response[1] === 0x00) { 41 | 42 | client.once('data', (status) => { 43 | console.log('Connection Status Frame', status); 44 | }); 45 | 46 | client.write(CONNECTION_REQUEST); 47 | 48 | } 49 | 50 | }); 51 | 52 | client.write(HANDSHAKE_REQUEST); 53 | 54 | }); 55 | 56 | -------------------------------------------------------------------------------- /weblog/articles/implementers-guide-to-socks/client.mjs: -------------------------------------------------------------------------------- 1 | // client.mjs 2 | import net from 'net'; 3 | import { SOCKS } from './SOCKS.mjs'; 4 | 5 | 6 | 7 | // Chapter: SOCKS Client 8 | let client = new net.createConnection({ 9 | host: 'localhost', 10 | port: 1080 11 | }, () => { 12 | 13 | let handshake = { 14 | headers: { 15 | 'auth': [ 'none' ] 16 | } 17 | }; 18 | 19 | // Chapter: Handshake Request 20 | console.log('Send Handshake Request', handshake); 21 | SOCKS.send(client, handshake); 22 | 23 | }); 24 | 25 | client.once('data', (response) => { 26 | 27 | client.allowHalfOpen = false; 28 | client.setTimeout(0); 29 | client.setNoDelay(true); 30 | client.setKeepAlive(true, 0); 31 | 32 | client.removeAllListeners('timeout'); 33 | client.removeAllListeners('data'); 34 | 35 | // Chapter: Handshake Response 36 | SOCKS.receive(client, response, (data) => { 37 | 38 | console.log('Receive Handshake Response', data); 39 | 40 | if (data.headers['@version'] === 0x05 && data.headers['auth'] === 'none') { 41 | 42 | // Chapter: Connection Status 43 | client.once('data', (status) => { 44 | 45 | SOCKS.receive(client, status, (data) => { 46 | 47 | console.log('Receive Connection Status', data); 48 | 49 | if (data.headers['@status'] === 'success') { 50 | console.log('Client would be ready to do a HTTP request to ' + data.payload.host + ':' + data.payload.port + ' now.'); 51 | // TODO: client.write(HTTP_REQUEST); 52 | client.destroy(); 53 | } else { 54 | console.error('Server responded with an Error: ' + data.headers['@status']); 55 | client.destroy(); 56 | } 57 | 58 | }); 59 | 60 | }); 61 | 62 | setTimeout(() => { 63 | 64 | let request = { 65 | headers: { 66 | '@method': 'connect' 67 | }, 68 | payload: { 69 | domain: 'cookie.engineer', 70 | port: 80 // HTTP 71 | } 72 | }; 73 | 74 | // Chapter: Connection Request 75 | console.log('Send Connection Request', request); 76 | SOCKS.send(client, request); 77 | 78 | }, 1000); 79 | 80 | } else { 81 | client.destroy(); 82 | } 83 | 84 | }); 85 | 86 | SOCKS.receive(response); 87 | 88 | }); 89 | 90 | client.on('error', () => {}); 91 | client.on('close', () => {}); 92 | client.on('timeout', () => client.destroy()); 93 | 94 | -------------------------------------------------------------------------------- /weblog/articles/intel-nuc-homeserver/fanless-intel-nuc-inside.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/intel-nuc-homeserver/fanless-intel-nuc-inside.jpg -------------------------------------------------------------------------------- /weblog/articles/intel-nuc-homeserver/fanless-intel-nuc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/intel-nuc-homeserver/fanless-intel-nuc.jpg -------------------------------------------------------------------------------- /weblog/articles/linux-assembly-part-4-arithmetic-operations.md: -------------------------------------------------------------------------------- 1 | 2 | ## Arithmetic Operations 3 | 4 | | Instruction | Description | 5 | | ADD dest, src | dest = dest + src | 6 | | SUB dest, src | dest = dest - src | 7 | | MUL reg | edx:eax = eax * reg | 8 | mul, add, etc 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /weblog/articles/linux-assembly/.gitignore: -------------------------------------------------------------------------------- 1 | /*.o 2 | /*.bin 3 | -------------------------------------------------------------------------------- /weblog/articles/linux-assembly/calculator.asm: -------------------------------------------------------------------------------- 1 | section .data 2 | ; Define our numbers 3 | num1: equ 13 4 | num2: equ 37 5 | 6 | ; Define our messages 7 | msg1: db "Sum is correct!" 8 | msg2: db "Sum is incorrect!" 9 | 10 | section .text 11 | global _start 12 | 13 | _start: 14 | 15 | mov rax, num1 16 | mov rbx, num2 17 | add rax, rbx ; add(rax, rbx) stores the result in rax 18 | 19 | cmp rax, 50 20 | je .print_correct 21 | jmp .print_incorrect 22 | 23 | .print_correct: 24 | 25 | mov rax, 1 26 | mov rdi, 1 27 | mov rsi, msg1 28 | mov rdx, 15 29 | syscall 30 | jmp .exit_correct 31 | 32 | .print_incorrect: 33 | 34 | mov rax, 1 35 | mov rdi, 1 36 | mov rsi, msg2 37 | mov rdx, 17 38 | syscall 39 | jmp .exit_incorrect 40 | 41 | .exit_correct: 42 | mov rax, 60 43 | mov rdi, 0 44 | syscall 45 | 46 | .exit_incorrect: 47 | mov rax, 60 48 | mov rdi, 1 49 | syscall 50 | -------------------------------------------------------------------------------- /weblog/articles/linux-assembly/hello-world.asm: -------------------------------------------------------------------------------- 1 | section .data 2 | msg db "Hello, World!" 3 | 4 | section .text 5 | global _start 6 | 7 | _start: 8 | mov rax, 1 ; syscall 1 "ksys_write(rdi, rsi, rdx)" 9 | mov rdi, 1 ; int 1 for standard output 10 | mov rsi, msg ; pointer to message 11 | mov rdx, 13 ; length of message 12 | syscall ; execute syscall stored in rax 13 | 14 | mov rax, 60 ; syscall 60 for "exit(rdi)" 15 | mov rdi, 0 ; int 0 for exit code 16 | syscall ; execute syscall stored in rax 17 | -------------------------------------------------------------------------------- /weblog/articles/linux-assembly/stack.asm: -------------------------------------------------------------------------------- 1 | 2 | section .text 3 | global _start 4 | 5 | _start: 6 | ; set two registers for demonstration 7 | mov rax, 13 8 | mov rdx, 37 9 | 10 | ; rax stored at address 0 * 8 11 | ; increment rsp address to where the value of 13 is 12 | push rax 13 | 14 | ; rdx stored at address 1 * 8 15 | ; increment rsp address to where the value of 37 is 16 | push rdx 17 | 18 | ; set rax to the value of [rsp + 8], which is 13 19 | mov rax, [rsp + 8] 20 | 21 | cmp rax, 13 22 | je .success 23 | jmp .failure 24 | 25 | .success: 26 | mov rax, 60 27 | mov rdi, 0 28 | syscall 29 | 30 | .failure: 31 | mov rax, 60 32 | mov rdi, 1 33 | syscall 34 | -------------------------------------------------------------------------------- /weblog/articles/maintenance-of-clearnets/first-time.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/maintenance-of-clearnets/first-time.jpg -------------------------------------------------------------------------------- /weblog/articles/maintenance-of-clearnets/heist-attack.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/maintenance-of-clearnets/heist-attack.pdf -------------------------------------------------------------------------------- /weblog/articles/maintenance-of-clearnets/maximum-security-prison.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/maintenance-of-clearnets/maximum-security-prison.jpg -------------------------------------------------------------------------------- /weblog/articles/maintenance-of-clearnets/telephone-operator-lady.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/maintenance-of-clearnets/telephone-operator-lady.jpg -------------------------------------------------------------------------------- /weblog/articles/mx518-repair-guide/01-mouse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/mx518-repair-guide/01-mouse.jpg -------------------------------------------------------------------------------- /weblog/articles/mx518-repair-guide/02-topshell.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/mx518-repair-guide/02-topshell.jpg -------------------------------------------------------------------------------- /weblog/articles/mx518-repair-guide/03-mousewheel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/mx518-repair-guide/03-mousewheel.jpg -------------------------------------------------------------------------------- /weblog/articles/mx518-repair-guide/04-components.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/mx518-repair-guide/04-components.jpg -------------------------------------------------------------------------------- /weblog/articles/pacman-backup/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/pacman-backup/screenshot.png -------------------------------------------------------------------------------- /weblog/articles/problems-with-web-browsers/firefox-cache-on-mobile-internet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/problems-with-web-browsers/firefox-cache-on-mobile-internet.png -------------------------------------------------------------------------------- /weblog/articles/problems-with-web-browsers/firefox-network-connection-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/problems-with-web-browsers/firefox-network-connection-error.png -------------------------------------------------------------------------------- /weblog/articles/problems-with-web-browsers/firefox-network-protocol-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/problems-with-web-browsers/firefox-network-protocol-error.png -------------------------------------------------------------------------------- /weblog/articles/problems-with-web-browsers/firefox-network-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/problems-with-web-browsers/firefox-network-settings.png -------------------------------------------------------------------------------- /weblog/articles/problems-with-web-browsers/stackoverflow-print-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/problems-with-web-browsers/stackoverflow-print-preview.png -------------------------------------------------------------------------------- /weblog/articles/problems-with-web-browsers/stealth-browser-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/problems-with-web-browsers/stealth-browser-settings.png -------------------------------------------------------------------------------- /weblog/articles/synaptics-touchpad-on-linux/70-synaptics.conf: -------------------------------------------------------------------------------- 1 | Section "InputClass" 2 | Identifier "touchpad catchall" 3 | Driver "synaptics" 4 | MatchIsTouchpad "on" 5 | MatchDevicePath "/dev/input/event*" 6 | EndSection 7 | 8 | Section "InputClass" 9 | Identifier "touchpad ignore duplicates" 10 | MatchIsTouchpad "on" 11 | MatchOS "Linux" 12 | MatchDevicePath "/dev/input/mouse*" 13 | Option "Ignore" "on" 14 | EndSection 15 | 16 | Section "InputClass" 17 | Identifier "default clickpad buttons" 18 | MatchDriver "synaptics" 19 | Option "ClickPad" "0" 20 | Option "PalmDetect" "1" 21 | Option "TouchpadOff" "0" 22 | Option "MinSpeed" "2.0" 23 | Option "MaxSpeed" "2.0" 24 | Option "TapButton1" "1" 25 | Option "TapButton2" "3" 26 | Option "TapButton3" "2" 27 | Option "AreaLeftEdge" "0" 28 | Option "AreaRightEdge" "5112" 29 | Option "AreaTopEdge" "0" 30 | Option "AreaBottomEdge" "4832" 31 | Option "VertTwoFingerScroll" "1" 32 | Option "VertEdgeScroll" "0" 33 | Option "VertScrollDelta" "-111" 34 | Option "HorizTwoFingerScroll" "1" 35 | Option "HorizEdgeScroll" "0" 36 | Option "HorizScrollDelta" "-111" 37 | EndSection 38 | 39 | Section "InputClass" 40 | Identifier "disable clickpad buttons on Apple touchpads" 41 | MatchDriver "synaptics" 42 | MatchProduct "Apple|bcm5974" 43 | Option "SoftButtonAreas" "0 0 0 0 0 0 0 0" 44 | EndSection 45 | -------------------------------------------------------------------------------- /weblog/articles/synaptics-touchpad-on-linux/lenovo-synaptics-touchpad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/synaptics-touchpad-on-linux/lenovo-synaptics-touchpad.jpg -------------------------------------------------------------------------------- /weblog/articles/your-definition-of-privacy-is-wrong/umatrix-usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/articles/your-definition-of-privacy-is-wrong/umatrix-usage.png -------------------------------------------------------------------------------- /weblog/design/editor/vera-mono.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/design/editor/vera-mono.woff -------------------------------------------------------------------------------- /weblog/design/editor/vera-mono.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cookiengineer/cookie.engineer/a4ca598f85c421ea44fc5e24627ad512f74c2040/weblog/design/editor/vera-mono.woff2 -------------------------------------------------------------------------------- /weblog/design/index.css: -------------------------------------------------------------------------------- 1 | 2 | section#welcome h1 { 3 | display: block; 4 | margin: 160px 0px 0px 0px; 5 | padding: 0px; 6 | font-family: 'museo-sans-500'; 7 | font-size: 40px; 8 | line-height: 48px; 9 | font-weight: 500; 10 | text-align: center; 11 | } 12 | 13 | section#weblog article ul { 14 | display: block; 15 | margin: 0px; 16 | padding: 1em 0px 0px 0px; 17 | list-style: none; 18 | } 19 | 20 | section#weblog article[data-result="false"] ul { 21 | display: none; 22 | } 23 | 24 | section#weblog article ul li b { 25 | display: inline-block; 26 | width: 8em; 27 | font-weight: 300; 28 | font-size: 16px; 29 | line-height: 20px; 30 | vertical-align: middle; 31 | } 32 | 33 | section#weblog article ul li a, 34 | section#weblot article ul li span { 35 | display: inline-block; 36 | width: calc(100% - 8em); 37 | font-size: 16px; 38 | line-height: 20px; 39 | vertical-align: middle; 40 | white-space: nowrap; 41 | text-overflow: ellipsis; 42 | overflow: hidden; 43 | } 44 | 45 | 46 | 47 | @media print { 48 | 49 | section#welcome { 50 | display: block; 51 | position: relative; 52 | width: 100vw; 53 | margin: 0px; 54 | padding: 0px; 55 | } 56 | 57 | section#welcome h1 { 58 | display: block; 59 | position: static; 60 | width: 100vw; 61 | height: 25vh; 62 | margin: 4em 0px 0px 0px; 63 | padding: 0px; 64 | font-size: 64px; 65 | line-height: 64px; 66 | text-align: center; 67 | vertical-align: middle; 68 | page-break-before: unset; 69 | page-break-after: unset; 70 | } 71 | 72 | section#welcome article { 73 | display: block; 74 | position: static; 75 | width: auto; 76 | margin: 6em 0px 0px 0px; 77 | padding: 0px; 78 | text-align: left; 79 | background: transparent; 80 | border-radius: 0px; 81 | break-before: auto; 82 | } 83 | 84 | section#weblog article, 85 | section#weblog article:nth-of-type(even) { 86 | display: block; 87 | position: static; 88 | width: 100vw; 89 | height: 25vh; 90 | margin: 0px; 91 | padding: 0px; 92 | } 93 | 94 | section#weblog article:nth-of-type(even) { 95 | page-break-after: unset; 96 | } 97 | 98 | } 99 | 100 | -------------------------------------------------------------------------------- /weblog/design/layout/article.js: -------------------------------------------------------------------------------- 1 | 2 | (function(global) { 3 | 4 | global.addEventListener('DOMContentLoaded', () => { 5 | 6 | let hljs = global.hljs || null; 7 | if (hljs !== null) { 8 | 9 | let codes = Array.from(document.querySelectorAll('pre[class]')); 10 | if (codes.length > 0) { 11 | 12 | codes.forEach((code) => { 13 | 14 | let lang = code.className || null; 15 | if (lang === 'javascript') { 16 | 17 | setTimeout(() => { 18 | 19 | Array.from(code.querySelectorAll('span.hljs-built_in')).forEach((node) => { 20 | 21 | let text = node.innerHTML || ''; 22 | if (text === 'console') { 23 | node.className += ' hljs-console'; 24 | } 25 | 26 | }); 27 | 28 | Array.from(code.querySelectorAll('span.hljs-keyword')).forEach((node) => { 29 | 30 | let text = node.innerHTML || ''; 31 | if (text === 'let') { 32 | node.className += ' hljs-let'; 33 | } else if (text === 'new') { 34 | node.className += ' hljs-new'; 35 | } else if (text === 'function') { 36 | node.className += ' hljs-function'; 37 | } 38 | 39 | }); 40 | 41 | Array.from(code.querySelectorAll('span.hljs-literal')).forEach((node) => { 42 | 43 | let text = node.innerHTML || ''; 44 | if (text === 'null') { 45 | node.className += ' hljs-null'; 46 | } 47 | 48 | }); 49 | 50 | }, 500); 51 | 52 | } 53 | 54 | if (lang !== 'plaintext') { 55 | hljs.highlightElement(code); 56 | } 57 | 58 | }); 59 | 60 | } 61 | 62 | } 63 | 64 | }, true); 65 | 66 | })(typeof window !== 'undefined' ? window : this); 67 | 68 | -------------------------------------------------------------------------------- /weblog/design/layout/highlight.css: -------------------------------------------------------------------------------- 1 | 2 | /* general */ 3 | .hljs {} 4 | .hljs-built_in { color: #ff5f87 } 5 | .hljs-title.class_ { color: #ff5f87 } 6 | .hljs-class .hljs-title { color: #ff5f87 } 7 | 8 | .hljs-class { color: #ff5f87 } 9 | .hljs-function { color: #d78787 } 10 | .hljs-keyword { color: #ff5f87 } 11 | .hljs-literal { color: #32afe5 } 12 | .hljs-number { color: #ff005f } 13 | .hljs-params { color: #ffffff } 14 | .hljs-regexp { color: #5fd75f } 15 | .hljs-string { color: #5fd75f } 16 | .hljs-subst { color: #ffffff } /* unsure about this? */ 17 | .hljs-symbol { color: #32afe5 } 18 | .hljs-title { color: #ffffff } 19 | .hljs-type { color: #d78787 } 20 | 21 | /* meta */ 22 | .hljs-comment { color: #afafaf } 23 | .hljs-doctag { color: #afafaf } 24 | .hljs-meta { color: #d78787 } 25 | .hljs-meta .hljs-keyword { color: #ff5f87 } 26 | .hljs-meta .hljs-string { color: #5fd75f } 27 | .hljs-section { color: #ffffff } 28 | .hljs-tag { color: #d78787 } 29 | .hljs-name { color: #ff5f87 } 30 | .hljs-builtin-name { color: #ff5f87 } 31 | .hljs-attr { color: #d78787 } 32 | .hljs-attribute { color: #d78787 } 33 | .hljs-variable { color: #ffffff } 34 | 35 | /* markup */ 36 | .hljs-bullet { color: #ffffff } 37 | .hljs-emphasis { font-style: italic } 38 | .hljs-formula { color: #ffffff } 39 | .hljs-link { text-decoration: underline } 40 | .hljs-quote { color: #afafaf } 41 | .hljs-strong { font-weight: bold } 42 | 43 | /* css */ 44 | .hljs-selector-tag { color: #d78787 } 45 | .hljs-selector-id { color: #d78787 } 46 | .hljs-selector-class { color: #5fd75f } 47 | .hljs-selector-attr { color: #5fd75f } 48 | .hljs-selector-pseudo { color: #ffffff } 49 | 50 | /* templates */ 51 | 52 | .hljs-template-tag { color: #d78787 } 53 | .hljs-template-variable { color: #ff5f87 } 54 | 55 | /* diff */ 56 | .hljs-addition { background-color: #5faf5f } 57 | .hljs-deletion { background-color: #5f0000 } 58 | 59 | 60 | 61 | /* FIXES */ 62 | 63 | pre.http { color: #5fd75f } 64 | pre.http .hljs-attribute { color: #ff5f87 } 65 | 66 | pre.javascript .hljs-attr { color: #ffffff } 67 | pre.javascript .hljs-console { color: #ffffff } 68 | pre.javascript .hljs-function { color: #d78787 } 69 | pre.javascript .hljs-let { color: #32afe5 } 70 | pre.javascript .hljs-new { color: #32afe5 } 71 | pre.javascript .hljs-null { color: #ff5f87 } 72 | pre.javascript .hljs-undefined { color: #ff5f87 } 73 | 74 | -------------------------------------------------------------------------------- /weblog/editor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Cookie Engineer's Crappy Web Log Editor 5 | 6 | 7 | 8 | 9 | 10 |
    11 | 12 | 13 |
    14 | 17 | 18 | 19 | --------------------------------------------------------------------------------