This commit is contained in:
parent
2fe8b81523
commit
1cd021d0a7
|
@ -4,7 +4,7 @@ A starter repository showing how to build a blog with the [Eleventy](https://www
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
* [Want a more generic/detailed getting started guide?](https://www.11ty.dev/docs/getting-started/)
|
- [Want a more generic/detailed getting started guide?](https://www.11ty.dev/docs/getting-started/)
|
||||||
|
|
||||||
1. Make a directory and navigate to it:
|
1. Make a directory and navigate to it:
|
||||||
|
|
||||||
|
|
170
_data/colors.js
170
_data/colors.js
|
@ -1,92 +1,92 @@
|
||||||
export default {
|
export default {
|
||||||
dark: {
|
dark: {
|
||||||
"source": "rootloops.sh",
|
source: "rootloops.sh",
|
||||||
"hex": {
|
hex: {
|
||||||
"background": "#0a0808",
|
background: "#0a0808",
|
||||||
"foreground": "#e7e1e2",
|
foreground: "#e7e1e2",
|
||||||
"cursor": "#c2b5b8",
|
cursor: "#c2b5b8",
|
||||||
"black": "#272022",
|
black: "#272022",
|
||||||
"red": "#cf5080",
|
red: "#cf5080",
|
||||||
"green": "#7b8d39",
|
green: "#7b8d39",
|
||||||
"yellow": "#b57235",
|
yellow: "#b57235",
|
||||||
"blue": "#3c8cbf",
|
blue: "#3c8cbf",
|
||||||
"magenta": "#9468d8",
|
magenta: "#9468d8",
|
||||||
"cyan": "#3b9586",
|
cyan: "#3b9586",
|
||||||
"white": "#c2b5b8",
|
white: "#c2b5b8",
|
||||||
"brightBlack": "#5a4e51",
|
brightBlack: "#5a4e51",
|
||||||
"brightRed": "#e26b95",
|
brightRed: "#e26b95",
|
||||||
"brightGreen": "#8fa445",
|
brightGreen: "#8fa445",
|
||||||
"brightYellow": "#cf8544",
|
brightYellow: "#cf8544",
|
||||||
"brightBlue": "#4fa1d7",
|
brightBlue: "#4fa1d7",
|
||||||
"brightMagenta": "#a782e5",
|
brightMagenta: "#a782e5",
|
||||||
"brightCyan": "#47ac9b",
|
brightCyan: "#47ac9b",
|
||||||
"brightWhite": "#f3f0f1"
|
brightWhite: "#f3f0f1",
|
||||||
|
},
|
||||||
|
hsl: {
|
||||||
|
background: "hsl(345.13, 15.37%, 3.54%)",
|
||||||
|
foreground: "hsl(344.94, 10.53%, 89.29%)",
|
||||||
|
cursor: "hsl(344.63, 9.37%, 73.52%)",
|
||||||
|
black: "hsl(344.1, 8.9%, 13.97%)",
|
||||||
|
red: "hsl(337.55, 56.97%, 56.34%)",
|
||||||
|
green: "hsl(72.88, 42.49%, 38.93%)",
|
||||||
|
yellow: "hsl(28.49, 54.76%, 45.89%)",
|
||||||
|
blue: "hsl(203.33, 52.42%, 49.09%)",
|
||||||
|
magenta: "hsl(264.05, 58.81%, 62.59%)",
|
||||||
|
cyan: "hsl(169.71, 43.35%, 40.84%)",
|
||||||
|
white: "hsl(344.63, 9.37%, 73.52%)",
|
||||||
|
brightBlack: "hsl(344.15, 7.1%, 32.99%)",
|
||||||
|
brightRed: "hsl(339.06, 67.64%, 65.41%)",
|
||||||
|
brightGreen: "hsl(72.99, 40.55%, 45.65%)",
|
||||||
|
brightYellow: "hsl(28.18, 58.94%, 53.93%)",
|
||||||
|
brightBlue: "hsl(203.73, 63.27%, 57.72%)",
|
||||||
|
brightMagenta: "hsl(262.71, 65.56%, 70.29%)",
|
||||||
|
brightCyan: "hsl(169.62, 41.51%, 47.79%)",
|
||||||
|
brightWhite: "hsl(345.03, 10.68%, 94.62%)",
|
||||||
},
|
},
|
||||||
"hsl": {
|
|
||||||
"background": "hsl(345.13, 15.37%, 3.54%)",
|
|
||||||
"foreground": "hsl(344.94, 10.53%, 89.29%)",
|
|
||||||
"cursor": "hsl(344.63, 9.37%, 73.52%)",
|
|
||||||
"black": "hsl(344.1, 8.9%, 13.97%)",
|
|
||||||
"red": "hsl(337.55, 56.97%, 56.34%)",
|
|
||||||
"green": "hsl(72.88, 42.49%, 38.93%)",
|
|
||||||
"yellow": "hsl(28.49, 54.76%, 45.89%)",
|
|
||||||
"blue": "hsl(203.33, 52.42%, 49.09%)",
|
|
||||||
"magenta": "hsl(264.05, 58.81%, 62.59%)",
|
|
||||||
"cyan": "hsl(169.71, 43.35%, 40.84%)",
|
|
||||||
"white": "hsl(344.63, 9.37%, 73.52%)",
|
|
||||||
"brightBlack": "hsl(344.15, 7.1%, 32.99%)",
|
|
||||||
"brightRed": "hsl(339.06, 67.64%, 65.41%)",
|
|
||||||
"brightGreen": "hsl(72.99, 40.55%, 45.65%)",
|
|
||||||
"brightYellow": "hsl(28.18, 58.94%, 53.93%)",
|
|
||||||
"brightBlue": "hsl(203.73, 63.27%, 57.72%)",
|
|
||||||
"brightMagenta": "hsl(262.71, 65.56%, 70.29%)",
|
|
||||||
"brightCyan": "hsl(169.62, 41.51%, 47.79%)",
|
|
||||||
"brightWhite": "hsl(345.03, 10.68%, 94.62%)"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
light: {
|
light: {
|
||||||
"source": "rootloops.sh",
|
source: "rootloops.sh",
|
||||||
"hex": {
|
hex: {
|
||||||
"background": "#f3f0f1",
|
background: "#f3f0f1",
|
||||||
"foreground": "#40373a",
|
foreground: "#40373a",
|
||||||
"cursor": "#74666a",
|
cursor: "#74666a",
|
||||||
"black": "#e7e1e2",
|
black: "#e7e1e2",
|
||||||
"red": "#cf5080",
|
red: "#cf5080",
|
||||||
"green": "#7b8d39",
|
green: "#7b8d39",
|
||||||
"yellow": "#b57235",
|
yellow: "#b57235",
|
||||||
"blue": "#3c8cbf",
|
blue: "#3c8cbf",
|
||||||
"magenta": "#9468d8",
|
magenta: "#9468d8",
|
||||||
"cyan": "#3b9586",
|
cyan: "#3b9586",
|
||||||
"white": "#74666a",
|
white: "#74666a",
|
||||||
"brightBlack": "#b5a7ab",
|
brightBlack: "#b5a7ab",
|
||||||
"brightRed": "#e26b95",
|
brightRed: "#e26b95",
|
||||||
"brightGreen": "#8fa445",
|
brightGreen: "#8fa445",
|
||||||
"brightYellow": "#cf8544",
|
brightYellow: "#cf8544",
|
||||||
"brightBlue": "#4fa1d7",
|
brightBlue: "#4fa1d7",
|
||||||
"brightMagenta": "#a782e5",
|
brightMagenta: "#a782e5",
|
||||||
"brightCyan": "#47ac9b",
|
brightCyan: "#47ac9b",
|
||||||
"brightWhite": "#272022"
|
brightWhite: "#272022",
|
||||||
},
|
},
|
||||||
"hsl": {
|
hsl: {
|
||||||
"background": "hsl(345.03, 10.68%, 94.62%)",
|
background: "hsl(345.03, 10.68%, 94.62%)",
|
||||||
"foreground": "hsl(344.11, 7.75%, 23.41%)",
|
foreground: "hsl(344.11, 7.75%, 23.41%)",
|
||||||
"cursor": "hsl(344.2, 6.49%, 42.82%)",
|
cursor: "hsl(344.2, 6.49%, 42.82%)",
|
||||||
"black": "hsl(344.94, 10.53%, 89.29%)",
|
black: "hsl(344.94, 10.53%, 89.29%)",
|
||||||
"red": "hsl(337.55, 56.97%, 56.34%)",
|
red: "hsl(337.55, 56.97%, 56.34%)",
|
||||||
"green": "hsl(72.88, 42.49%, 38.93%)",
|
green: "hsl(72.88, 42.49%, 38.93%)",
|
||||||
"yellow": "hsl(28.49, 54.76%, 45.89%)",
|
yellow: "hsl(28.49, 54.76%, 45.89%)",
|
||||||
"blue": "hsl(203.33, 52.42%, 49.09%)",
|
blue: "hsl(203.33, 52.42%, 49.09%)",
|
||||||
"magenta": "hsl(264.05, 58.81%, 62.59%)",
|
magenta: "hsl(264.05, 58.81%, 62.59%)",
|
||||||
"cyan": "hsl(169.71, 43.35%, 40.84%)",
|
cyan: "hsl(169.71, 43.35%, 40.84%)",
|
||||||
"white": "hsl(344.2, 6.49%, 42.82%)",
|
white: "hsl(344.2, 6.49%, 42.82%)",
|
||||||
"brightBlack": "hsl(344.53, 8.76%, 68.33%)",
|
brightBlack: "hsl(344.53, 8.76%, 68.33%)",
|
||||||
"brightRed": "hsl(339.06, 67.64%, 65.41%)",
|
brightRed: "hsl(339.06, 67.64%, 65.41%)",
|
||||||
"brightGreen": "hsl(72.99, 40.55%, 45.65%)",
|
brightGreen: "hsl(72.99, 40.55%, 45.65%)",
|
||||||
"brightYellow": "hsl(28.18, 58.94%, 53.93%)",
|
brightYellow: "hsl(28.18, 58.94%, 53.93%)",
|
||||||
"brightBlue": "hsl(203.73, 63.27%, 57.72%)",
|
brightBlue: "hsl(203.73, 63.27%, 57.72%)",
|
||||||
"brightMagenta": "hsl(262.71, 65.56%, 70.29%)",
|
brightMagenta: "hsl(262.71, 65.56%, 70.29%)",
|
||||||
"brightCyan": "hsl(169.62, 41.51%, 47.79%)",
|
brightCyan: "hsl(169.62, 41.51%, 47.79%)",
|
||||||
"brightWhite": "hsl(344.1, 8.9%, 13.97%)"
|
brightWhite: "hsl(344.1, 8.9%, 13.97%)",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -6,6 +6,6 @@ export default {
|
||||||
author: {
|
author: {
|
||||||
name: "Saji",
|
name: "Saji",
|
||||||
email: "saji@saji.dev",
|
email: "saji@saji.dev",
|
||||||
url: "https://saji.dev/about-me/"
|
url: "https://saji.dev/about-me/",
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ layout: layouts/home.njk
|
||||||
permalink: 404.html
|
permalink: 404.html
|
||||||
eleventyExcludeFromCollections: true
|
eleventyExcludeFromCollections: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# Content not found.
|
# Content not found.
|
||||||
|
|
||||||
Go <a href="/">home</a>.
|
Go <a href="/">home</a>.
|
||||||
|
|
|
@ -4,6 +4,7 @@ eleventyNavigation:
|
||||||
key: About Me
|
key: About Me
|
||||||
order: 3
|
order: 3
|
||||||
---
|
---
|
||||||
|
|
||||||
# About Me
|
# About Me
|
||||||
|
|
||||||
I am a person that writes stuff.
|
I am a person that writes stuff.
|
||||||
|
|
|
@ -6,6 +6,4 @@ tags:
|
||||||
- project
|
- project
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
This is a test
|
This is a test
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
export default {
|
export default {
|
||||||
tags: [
|
tags: ["posts"],
|
||||||
"posts"
|
layout: "layouts/post.njk",
|
||||||
],
|
|
||||||
"layout": "layouts/post.njk",
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@ has been documented to death by skids, I haven't seen anyone reference this yet.
|
||||||
I'm sure someone is using it, since it's powerful.
|
I'm sure someone is using it, since it's powerful.
|
||||||
|
|
||||||
Case in point:
|
Case in point:
|
||||||
|
|
||||||
```
|
```
|
||||||
/"[a-z]{4}(?: [a-z]{4}){3}"/ language:Python SMTP
|
/"[a-z]{4}(?: [a-z]{4}){3}"/ language:Python SMTP
|
||||||
```
|
```
|
||||||
|
|
|
@ -13,7 +13,7 @@ Part one focuses on the image format.
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
*[ITAR]: International Traffic in Arms Regulations
|
\*[ITAR]: International Traffic in Arms Regulations
|
||||||
In the past few years, Chinese manufacturers have brought cheap, performant microbolometer arrays to the consumer market.
|
In the past few years, Chinese manufacturers have brought cheap, performant microbolometer arrays to the consumer market.
|
||||||
These arrays are higher resolution and faster framerates than what can reasonably be acquired in the West - mostly due
|
These arrays are higher resolution and faster framerates than what can reasonably be acquired in the West - mostly due
|
||||||
to low competition and ITAR restrictions. Most popular are the low-cost modules by Infiray, which provides whitelabel solutions
|
to low competition and ITAR restrictions. Most popular are the low-cost modules by Infiray, which provides whitelabel solutions
|
||||||
|
@ -35,10 +35,8 @@ odd phone app. However this choice seems less popular on forums and there is no
|
||||||
reverse engineering project that exists already, so we'll have to start from
|
reverse engineering project that exists already, so we'll have to start from
|
||||||
scratch.
|
scratch.
|
||||||
|
|
||||||
|
|
||||||
# Getting the picture
|
# Getting the picture
|
||||||
|
|
||||||
|
|
||||||
To start with something simple, lets figure out how their image format works. They call it "radiometric JPEG". This
|
To start with something simple, lets figure out how their image format works. They call it "radiometric JPEG". This
|
||||||
isn't to be confused with FLIR's RJPEG format, which is already well understood.. When using regular image viewers,
|
isn't to be confused with FLIR's RJPEG format, which is already well understood.. When using regular image viewers,
|
||||||
we get a screenshot of the display. Where things get interesting is when we open the image with the Hikmicro Analyzer software, we can see the full
|
we get a screenshot of the display. Where things get interesting is when we open the image with the Hikmicro Analyzer software, we can see the full
|
||||||
|
@ -69,9 +67,3 @@ Well that's something. It's not perfect, but it means that our thermal data is r
|
||||||
# I'm hexing here
|
# I'm hexing here
|
||||||
|
|
||||||
Imhex is pretty great. You can perform a lot of analysis without needing other tools.
|
Imhex is pretty great. You can perform a lot of analysis without needing other tools.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ complex Ansible playbooks. While I don't think NixOS is ready for
|
||||||
personal computers, it absolutely makes sense on less dynamic devices
|
personal computers, it absolutely makes sense on less dynamic devices
|
||||||
like servers or embedded-ish machines.
|
like servers or embedded-ish machines.
|
||||||
|
|
||||||
|
|
||||||
We can use NixOS and nixpkgs to derive a fully defined operating system and services.
|
We can use NixOS and nixpkgs to derive a fully defined operating system and services.
|
||||||
Then, we can:
|
Then, we can:
|
||||||
|
|
||||||
|
@ -118,12 +117,10 @@ $ ls /nix/store | grep myblog
|
||||||
mqhssdlmg9f03avpajwcqaah2apknl02-myblog
|
mqhssdlmg9f03avpajwcqaah2apknl02-myblog
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Before we go any further, let's set up the nginx server,
|
Before we go any further, let's set up the nginx server,
|
||||||
as well as a well-known path for our website. I'll also
|
as well as a well-known path for our website. I'll also
|
||||||
add a user here that we can use to deploy.
|
add a user here that we can use to deploy.
|
||||||
|
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
|
@ -194,17 +191,15 @@ in
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Now we have a scoped user, with an ssh key authorized. It needs a shell so we can actually log
|
Now we have a scoped user, with an ssh key authorized. It needs a shell so we can actually log
|
||||||
in remotely.
|
in remotely.
|
||||||
The last step is creating that symlink. This is where the concept of "activation" comes into play.
|
The last step is creating that symlink. This is where the concept of "activation" comes into play.
|
||||||
|
|
||||||
|
|
||||||
For NixOS, `deploy-rs` activation just calls `switch-to-configuration` to make
|
For NixOS, `deploy-rs` activation just calls `switch-to-configuration` to make
|
||||||
the system change the profile. We can effectively do whatever we want here.
|
the system change the profile. We can effectively do whatever we want here.
|
||||||
|
|
||||||
|
|
||||||
Reading the [custom activator](https://github.com/serokell/deploy-rs/blob/aa07eb05537d4cd025e2310397a6adcedfe72c76/flake.nix#L58C13-L96C17) source:
|
Reading the [custom activator](https://github.com/serokell/deploy-rs/blob/aa07eb05537d4cd025e2310397a6adcedfe72c76/flake.nix#L58C13-L96C17) source:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
custom = {
|
custom = {
|
||||||
__functor = customSelf: base: activate:
|
__functor = customSelf: base: activate:
|
||||||
|
@ -246,7 +241,6 @@ custom = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
This is a bit difficult to parse because there's the whole `__functor` bit.
|
This is a bit difficult to parse because there's the whole `__functor` bit.
|
||||||
Essentially, we use `buildEnv` to add some new scripts to the `base` package,
|
Essentially, we use `buildEnv` to add some new scripts to the `base` package,
|
||||||
which are then used to call `activate`, which can be a shell script or a binary.
|
which are then used to call `activate`, which can be a shell script or a binary.
|
||||||
|
@ -314,7 +308,6 @@ The chain looks like this:
|
||||||
A profile is just a symlink to a derivation in the nix store. One layer of indirection
|
A profile is just a symlink to a derivation in the nix store. One layer of indirection
|
||||||
exists to make rollbacks easier.
|
exists to make rollbacks easier.
|
||||||
|
|
||||||
|
|
||||||
# End
|
# End
|
||||||
|
|
||||||
I hope this was useful for you. I think non-root deployment is
|
I hope this was useful for you. I think non-root deployment is
|
||||||
|
|
|
@ -140,4 +140,3 @@ to hack around that with a shim but that's a problem for later. It works
|
||||||
fine at 9600 baud using software flow control.
|
fine at 9600 baud using software flow control.
|
||||||
|
|
||||||
To the folks who rave about the terminals of yore, I get it now.
|
To the folks who rave about the terminals of yore, I get it now.
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@ description: Bringing modern synthesis to 30-year old technology with Yosys and
|
||||||
date: 2024-06-14
|
date: 2024-06-14
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GAL/PALs are ancient chips designed to implement custom logic as a precursor to CPLDs and FPGAs.
|
GAL/PALs are ancient chips designed to implement custom logic as a precursor to CPLDs and FPGAs.
|
||||||
They can implement any combinational logic using a Sum-of-Products architecture and a grid of wires
|
They can implement any combinational logic using a Sum-of-Products architecture and a grid of wires
|
||||||
with certain wires being connected at different coordinates:
|
with certain wires being connected at different coordinates:
|
||||||
|
@ -41,11 +39,9 @@ DESCRIPTION
|
||||||
Simple test of combinatorial logic.
|
Simple test of combinatorial logic.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
I don't want to deal with this. It's annoying to think about. What if we could create our own Verilog flow for GAL chips?
|
I don't want to deal with this. It's annoying to think about. What if we could create our own Verilog flow for GAL chips?
|
||||||
Then we could take advantage of the simulation and synthesis capabilities, which would make these chips a bit more useful.
|
Then we could take advantage of the simulation and synthesis capabilities, which would make these chips a bit more useful.
|
||||||
|
|
||||||
|
|
||||||
# The idea
|
# The idea
|
||||||
|
|
||||||
We use Yosys to synthesize Verilog, and do technology-mapping onto a set of primitive blocks that are then mapped by a custom tool.
|
We use Yosys to synthesize Verilog, and do technology-mapping onto a set of primitive blocks that are then mapped by a custom tool.
|
||||||
|
@ -54,20 +50,15 @@ onto actual positions based on a pin constraints file.
|
||||||
|
|
||||||
There's two components - Yosys technology mapping, and writing a "place-and-route" tool. We'll start with Yosys.
|
There's two components - Yosys technology mapping, and writing a "place-and-route" tool. We'll start with Yosys.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Yosys Technology Mapping
|
## Yosys Technology Mapping
|
||||||
|
|
||||||
This process is cursed and low level, but it works a little like this:
|
This process is cursed and low level, but it works a little like this:
|
||||||
|
|
||||||
- Yosys takes a generic synthesis pass at a netlist, which simplifies the design without looking at any physical implementation
|
- Yosys takes a generic synthesis pass at a netlist, which simplifies the design without looking at any physical implementation
|
||||||
- The simplified design is then mapped into Verilog-based "blocks", which could be things like AND gates, or complex blocks like a LUT.
|
- The simplified design is then mapped into Verilog-based "blocks", which could be things like AND gates, or complex blocks like a LUT.
|
||||||
This process turns generic blocks like an adder into a set of gates.
|
This process turns generic blocks like an adder into a set of gates.
|
||||||
- certain sequences of gates are then grouped and unified in the "extract" pass. Extraction would convert an operation like `mul -> add`
|
- certain sequences of gates are then grouped and unified in the "extract" pass. Extraction would convert an operation like `mul -> add`
|
||||||
into a single `mul_add` block.
|
into a single `mul_add` block.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## A history lesson
|
## A history lesson
|
||||||
|
|
||||||
|
@ -127,7 +118,6 @@ logic chip, changing the function depending on what you need. Additionally,
|
||||||
GALs operate at 5 volts is useful when interfacing with older systems and
|
GALs operate at 5 volts is useful when interfacing with older systems and
|
||||||
removes the need for a level shifter.
|
removes the need for a level shifter.
|
||||||
|
|
||||||
|
|
||||||
In practice, this isn't all great. Programming GALs is an exercise in frustration.
|
In practice, this isn't all great. Programming GALs is an exercise in frustration.
|
||||||
Take a look at a basic combinatorial assembly file:
|
Take a look at a basic combinatorial assembly file:
|
||||||
|
|
||||||
|
@ -159,18 +149,16 @@ test this in a larger system (we'll get back to this). Compared to the Verilog
|
||||||
flow, with simulation, testbenches, and synthesis, the raw assembly is stuck in
|
flow, with simulation, testbenches, and synthesis, the raw assembly is stuck in
|
||||||
the 80s and requires manual logic simplification.
|
the 80s and requires manual logic simplification.
|
||||||
|
|
||||||
Verilog compilers for GALs *did exist*, but they ran on old-as-dirt systems,
|
Verilog compilers for GALs _did exist_, but they ran on old-as-dirt systems,
|
||||||
didn't have any significant optimization capabilities, and were almost always
|
didn't have any significant optimization capabilities, and were almost always
|
||||||
proprietary. What if we could make our own open-source Verilog flow for GAL
|
proprietary. What if we could make our own open-source Verilog flow for GAL
|
||||||
chips? Then we could write test benches in Verilog, map complex designs onto
|
chips? Then we could write test benches in Verilog, map complex designs onto
|
||||||
the chip, and even integrate our designs with FPGAs later down the line.
|
the chip, and even integrate our designs with FPGAs later down the line.
|
||||||
|
|
||||||
|
|
||||||
# The idea
|
# The idea
|
||||||
|
|
||||||
GAL assembly appears occasionally when working with older systems, especially in a retro emulation context.
|
GAL assembly appears occasionally when working with older systems, especially in a retro emulation context.
|
||||||
|
|
||||||
|
|
||||||
# Is this useful?
|
# Is this useful?
|
||||||
|
|
||||||
Not particularly.
|
Not particularly.
|
||||||
|
|
|
@ -15,8 +15,8 @@ C interop, interesting features, and fast. Some of the headlines:
|
||||||
|
|
||||||
- `comptime`: Lispers are in shambles. Run Zig code to generate Zig code.
|
- `comptime`: Lispers are in shambles. Run Zig code to generate Zig code.
|
||||||
- Cross compilation. For real. Not Rust cross where you need to find a sysroot.
|
- Cross compilation. For real. Not Rust cross where you need to find a sysroot.
|
||||||
Not Go cross locking you out of CGO. You can literally change a variable and make
|
Not Go cross locking you out of CGO. You can literally change a variable and make
|
||||||
a Mac binary on Windows like it's nothing.
|
a Mac binary on Windows like it's nothing.
|
||||||
- Web target, both WASI and freestanding.
|
- Web target, both WASI and freestanding.
|
||||||
- SIMD Vectors? We take those I guess.
|
- SIMD Vectors? We take those I guess.
|
||||||
- It's got a build/test system built in. More on that later.
|
- It's got a build/test system built in. More on that later.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export default {
|
export default {
|
||||||
tags: [
|
tags: [],
|
||||||
],
|
layout: "layouts/deck.njk",
|
||||||
"layout": "layouts/deck.njk",
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
<section>
|
<section>
|
||||||
<h2>Object (dis)orientation</h2>
|
<h2>Object (dis)orientation</h2>
|
||||||
<h6> How to survive a "post-OO" world</h6>
|
<h6>How to survive a "post-OO" world</h6>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<section>
|
<section>Class/Inheritance has challenges</section>
|
||||||
Class/Inheritance has challenges
|
|
||||||
</section>
|
|
||||||
<section>
|
<section>
|
||||||
Combining Data + Code
|
Combining Data + Code
|
||||||
<pre><code data-trim data-noescape data-line-numbers="5|7-9">
|
<pre><code data-trim data-noescape data-line-numbers="5|7-9">
|
||||||
|
@ -20,21 +18,32 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
</code></pre>
|
</code></pre>
|
||||||
<p class="fragment">You have to know if this is an "interface", abstract class, or regular class.</p>
|
<p class="fragment">
|
||||||
<small class="fragment">(it's an abstract class, since <code>makeSound</code> is pure virtual)</small>
|
You have to know if this is an "interface", abstract class, or regular
|
||||||
|
class.
|
||||||
|
</p>
|
||||||
|
<small class="fragment"
|
||||||
|
>(it's an abstract class, since <code>makeSound</code> is pure
|
||||||
|
virtual)</small
|
||||||
|
>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<p> A class can be one of many things </p>
|
<p>A class can be one of many things</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Interface - abstract class with no members, and purely virtual </li>
|
<li>Interface - abstract class with no members, and purely virtual</li>
|
||||||
<li>Abstract Class - class with <em>some</em> pure virtual methods </li>
|
<li>Abstract Class - class with <em>some</em> pure virtual methods</li>
|
||||||
<li>"Regular" Class - class that is standalone and is fully implemented </li>
|
<li>
|
||||||
|
"Regular" Class - class that is standalone and is fully implemented
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<small class="fragment">These concepts all exist under the <code>class</code> keyword </small>
|
<small class="fragment"
|
||||||
|
>These concepts all exist under the <code>class</code> keyword
|
||||||
|
</small>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
In Rust, you trade <em>Inheritance</em> for <em>Traits</em> and <em>Types</em>.
|
In Rust, you trade <em>Inheritance</em> for <em>Traits</em> and
|
||||||
|
<em>Types</em>.
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
@ -63,10 +72,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<p> And can be used statically <em>or</em> dynamically!</p>
|
<p>And can be used statically <em>or</em> dynamically!</p>
|
||||||
<pre><code data-trim>
|
<pre><code data-trim>
|
||||||
fn static_mammal<T: Mammal>(m: T) {
|
fn static_mammal<T: Mammal>(m: T) {
|
||||||
// the type of T must be known at compile time.
|
// the type of T must be known at compile time.
|
||||||
|
@ -77,4 +85,3 @@
|
||||||
</code></pre>
|
</code></pre>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ eleventyNavigation:
|
||||||
key: Now
|
key: Now
|
||||||
order: 4
|
order: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
## Save Slot 0
|
## Save Slot 0
|
||||||
|
|
||||||
Rate-Monotonic scheduling my life.
|
Rate-Monotonic scheduling my life.
|
||||||
|
|
|
@ -3,43 +3,49 @@ export function eleventyComputedPermalink() {
|
||||||
// `addGlobalData` acts like a global data file and runs the top level function it receives.
|
// `addGlobalData` acts like a global data file and runs the top level function it receives.
|
||||||
return (data) => {
|
return (data) => {
|
||||||
// Always skip during non-watch/serve builds
|
// Always skip during non-watch/serve builds
|
||||||
if(data.draft && !process.env.BUILD_DRAFTS) {
|
if (data.draft && !process.env.BUILD_DRAFTS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.permalink;
|
return data.permalink;
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
export function eleventyComputedExcludeFromCollections() {
|
export function eleventyComputedExcludeFromCollections() {
|
||||||
// When using `addGlobalData` and you *want* to return a function, you must nest functions like this.
|
// When using `addGlobalData` and you *want* to return a function, you must nest functions like this.
|
||||||
// `addGlobalData` acts like a global data file and runs the top level function it receives.
|
// `addGlobalData` acts like a global data file and runs the top level function it receives.
|
||||||
return (data) => {
|
return (data) => {
|
||||||
// Always exclude from non-watch/serve builds
|
// Always exclude from non-watch/serve builds
|
||||||
if(data.draft && !process.env.BUILD_DRAFTS) {
|
if (data.draft && !process.env.BUILD_DRAFTS) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.eleventyExcludeFromCollections;
|
return data.eleventyExcludeFromCollections;
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
export default function (eleventyConfig) {
|
export default function (eleventyConfig) {
|
||||||
eleventyConfig.addGlobalData("eleventyComputed.permalink", eleventyComputedPermalink);
|
eleventyConfig.addGlobalData(
|
||||||
eleventyConfig.addGlobalData("eleventyComputed.eleventyExcludeFromCollections", eleventyComputedExcludeFromCollections);
|
"eleventyComputed.permalink",
|
||||||
|
eleventyComputedPermalink,
|
||||||
|
);
|
||||||
|
eleventyConfig.addGlobalData(
|
||||||
|
"eleventyComputed.eleventyExcludeFromCollections",
|
||||||
|
eleventyComputedExcludeFromCollections,
|
||||||
|
);
|
||||||
|
|
||||||
let logged = false;
|
let logged = false;
|
||||||
eleventyConfig.on("eleventy.before", ({runMode}) => {
|
eleventyConfig.on("eleventy.before", ({ runMode }) => {
|
||||||
let text = "Excluding";
|
let text = "Excluding";
|
||||||
// Only show drafts in serve/watch modes
|
// Only show drafts in serve/watch modes
|
||||||
if(runMode === "serve" || runMode === "watch") {
|
if (runMode === "serve" || runMode === "watch") {
|
||||||
process.env.BUILD_DRAFTS = true;
|
process.env.BUILD_DRAFTS = true;
|
||||||
text = "Including";
|
text = "Including";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only log once.
|
// Only log once.
|
||||||
if(!logged) {
|
if (!logged) {
|
||||||
console.log( `[11ty/eleventy-base-blog] ${text} drafts.` );
|
console.log(`[11ty/eleventy-base-blog] ${text} drafts.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
logged = true;
|
logged = true;
|
||||||
|
|
|
@ -11,13 +11,12 @@ import pluginNavigation from "@11ty/eleventy-navigation";
|
||||||
import { EleventyHtmlBasePlugin } from "@11ty/eleventy";
|
import { EleventyHtmlBasePlugin } from "@11ty/eleventy";
|
||||||
import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
|
import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
|
||||||
|
|
||||||
|
|
||||||
import pluginDrafts from "./eleventy.config.drafts.js";
|
import pluginDrafts from "./eleventy.config.drafts.js";
|
||||||
|
|
||||||
import fs from 'fs/promises'
|
import fs from "fs/promises";
|
||||||
|
|
||||||
/** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */
|
/** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */
|
||||||
export default async function(eleventyConfig) {
|
export default async function (eleventyConfig) {
|
||||||
// Copy the contents of the `public` folder to the output folder
|
// Copy the contents of the `public` folder to the output folder
|
||||||
// For example, `./public/css/` ends up in `_site/css/`
|
// For example, `./public/css/` ends up in `_site/css/`
|
||||||
eleventyConfig.addPassthroughCopy({
|
eleventyConfig.addPassthroughCopy({
|
||||||
|
@ -32,30 +31,27 @@ export default async function(eleventyConfig) {
|
||||||
eleventyConfig.addPlugin(pluginDrafts);
|
eleventyConfig.addPlugin(pluginDrafts);
|
||||||
// eleventyConfig.addPlugin(pluginFonts);
|
// eleventyConfig.addPlugin(pluginFonts);
|
||||||
// Official plugins
|
// Official plugins
|
||||||
let mkFeed = function(type, path) {
|
let mkFeed = function (type, path) {
|
||||||
eleventyConfig.addPlugin(feedPlugin, {
|
eleventyConfig.addPlugin(feedPlugin, {
|
||||||
type: type,
|
type: type,
|
||||||
outputPath: path,
|
outputPath: path,
|
||||||
collection: {
|
collection: {
|
||||||
name: "posts",
|
name: "posts",
|
||||||
limit: 0
|
limit: 0,
|
||||||
},
|
},
|
||||||
metadata: {
|
metadata: {
|
||||||
title: "Musings",
|
title: "Musings",
|
||||||
base: "https://saji.dev",
|
base: "https://saji.dev",
|
||||||
language: "en",
|
language: "en",
|
||||||
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
mkFeed("rss", "/rss.feed.xml");
|
mkFeed("rss", "/rss.feed.xml");
|
||||||
mkFeed("atom", "/atom.feed.xml");
|
mkFeed("atom", "/atom.feed.xml");
|
||||||
mkFeed("json", "/feed.json");
|
mkFeed("json", "/feed.json");
|
||||||
|
|
||||||
eleventyConfig.addPlugin(pluginSyntaxHighlight, {
|
eleventyConfig.addPlugin(pluginSyntaxHighlight, {
|
||||||
preAttributes: { tabindex: 0 }
|
preAttributes: { tabindex: 0 },
|
||||||
});
|
});
|
||||||
eleventyConfig.addPlugin(pluginNavigation);
|
eleventyConfig.addPlugin(pluginNavigation);
|
||||||
eleventyConfig.addPlugin(EleventyHtmlBasePlugin);
|
eleventyConfig.addPlugin(EleventyHtmlBasePlugin);
|
||||||
|
@ -68,20 +64,20 @@ export default async function(eleventyConfig) {
|
||||||
loading: "lazy",
|
loading: "lazy",
|
||||||
decoding: "async",
|
decoding: "async",
|
||||||
sizes: "auto",
|
sizes: "auto",
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Filters
|
// Filters
|
||||||
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
|
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
|
||||||
// Formatting tokens for Luxon: https://moment.github.io/luxon/#/formatting?id=table-of-tokens
|
// Formatting tokens for Luxon: https://moment.github.io/luxon/#/formatting?id=table-of-tokens
|
||||||
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(format || "dd LLLL yyyy");
|
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(
|
||||||
|
format || "dd LLLL yyyy",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
eleventyConfig.addFilter('htmlDateString', (dateObj) => {
|
eleventyConfig.addFilter("htmlDateString", (dateObj) => {
|
||||||
// dateObj input: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
|
// dateObj input: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
|
||||||
return DateTime.fromJSDate(dateObj, { zone: 'utc' }).toFormat('yyyy-LL-dd');
|
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toFormat("yyyy-LL-dd");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get the first `n` elements of a collection.
|
// Get the first `n` elements of a collection.
|
||||||
|
@ -102,21 +98,23 @@ export default async function(eleventyConfig) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Return all the tags used in a collection
|
// Return all the tags used in a collection
|
||||||
eleventyConfig.addFilter("getAllTags", collection => {
|
eleventyConfig.addFilter("getAllTags", (collection) => {
|
||||||
let tagSet = new Set();
|
let tagSet = new Set();
|
||||||
for (let item of collection) {
|
for (let item of collection) {
|
||||||
(item.data.tags || []).forEach(tag => tagSet.add(tag));
|
(item.data.tags || []).forEach((tag) => tagSet.add(tag));
|
||||||
}
|
}
|
||||||
return Array.from(tagSet);
|
return Array.from(tagSet);
|
||||||
});
|
});
|
||||||
|
|
||||||
eleventyConfig.addFilter("filterTagList", function filterTagList(tags) {
|
eleventyConfig.addFilter("filterTagList", function filterTagList(tags) {
|
||||||
return (tags || []).filter(tag => ["all", "nav", "post", "posts"].indexOf(tag) === -1);
|
return (tags || []).filter(
|
||||||
|
(tag) => ["all", "nav", "post", "posts"].indexOf(tag) === -1,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mdIt;
|
let mdIt;
|
||||||
// Customize Markdown library settings:
|
// Customize Markdown library settings:
|
||||||
eleventyConfig.amendLibrary("md", mdLib => {
|
eleventyConfig.amendLibrary("md", (mdLib) => {
|
||||||
// hack to let us use the markdown renderer for later.
|
// hack to let us use the markdown renderer for later.
|
||||||
mdIt = mdLib;
|
mdIt = mdLib;
|
||||||
mdLib.use(markdownItAnchor, {
|
mdLib.use(markdownItAnchor, {
|
||||||
|
@ -127,23 +125,25 @@ export default async function(eleventyConfig) {
|
||||||
ariaHidden: false,
|
ariaHidden: false,
|
||||||
}),
|
}),
|
||||||
level: [1, 2, 3, 4],
|
level: [1, 2, 3, 4],
|
||||||
slugify: eleventyConfig.getFilter("slugify")
|
slugify: eleventyConfig.getFilter("slugify"),
|
||||||
});
|
});
|
||||||
mdLib.use(markdownItAbbr);
|
mdLib.use(markdownItAbbr);
|
||||||
mdLib.use(markdownItKatex.default);
|
mdLib.use(markdownItKatex.default);
|
||||||
});
|
});
|
||||||
|
|
||||||
eleventyConfig.addShortcode("currentBuildDate", () => {
|
eleventyConfig.addShortcode("currentBuildDate", () => {
|
||||||
return (new Date()).toISOString();
|
return new Date().toISOString();
|
||||||
})
|
});
|
||||||
|
|
||||||
eleventyConfig.addShortcode("includeRaw", async (file) => fs.readFile(file, "utf8"));
|
eleventyConfig.addShortcode("includeRaw", async (file) =>
|
||||||
|
fs.readFile(file, "utf8"),
|
||||||
|
);
|
||||||
|
|
||||||
//eleventyConfig.addPairedShortcode("section", async (content, transition = "none") => {
|
//eleventyConfig.addPairedShortcode("section", async (content, transition = "none") => {
|
||||||
// return `<section data-transition=${transition}> ${mdIt.renderInline(content)} </section>`;
|
// return `<section data-transition=${transition}> ${mdIt.renderInline(content)} </section>`;
|
||||||
//})
|
//})
|
||||||
//
|
//
|
||||||
eleventyConfig.addPairedShortcode("callout", function(content) {
|
eleventyConfig.addPairedShortcode("callout", function (content) {
|
||||||
// The 'content' variable holds the text/HTML placed between
|
// The 'content' variable holds the text/HTML placed between
|
||||||
// {% callout %} and {% endcallout %}
|
// {% callout %} and {% endcallout %}
|
||||||
// We wrap it with our div structure.
|
// We wrap it with our div structure.
|
||||||
|
@ -165,12 +165,7 @@ export default async function(eleventyConfig) {
|
||||||
return {
|
return {
|
||||||
// Control which files Eleventy will process
|
// Control which files Eleventy will process
|
||||||
// e.g.: *.md, *.njk, *.html, *.liquid
|
// e.g.: *.md, *.njk, *.html, *.liquid
|
||||||
templateFormats: [
|
templateFormats: ["md", "njk", "html", "liquid"],
|
||||||
"md",
|
|
||||||
"njk",
|
|
||||||
"html",
|
|
||||||
"liquid",
|
|
||||||
],
|
|
||||||
|
|
||||||
// Pre-process *.md files with: (default: `liquid`)
|
// Pre-process *.md files with: (default: `liquid`)
|
||||||
markdownTemplateEngine: "njk",
|
markdownTemplateEngine: "njk",
|
||||||
|
@ -183,7 +178,7 @@ export default async function(eleventyConfig) {
|
||||||
input: "content", // default: "."
|
input: "content", // default: "."
|
||||||
includes: "../_includes", // default: "_includes"
|
includes: "../_includes", // default: "_includes"
|
||||||
data: "../_data", // default: "_data"
|
data: "../_data", // default: "_data"
|
||||||
output: "_site"
|
output: "_site",
|
||||||
},
|
},
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
@ -198,4 +193,4 @@ export default async function(eleventyConfig) {
|
||||||
// folder name and does **not** affect where things go in the output folder.
|
// folder name and does **not** affect where things go in the output folder.
|
||||||
pathPrefix: "/",
|
pathPrefix: "/",
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
31
flake.nix
31
flake.nix
|
@ -6,29 +6,42 @@
|
||||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, deploy-rs, systems, treefmt-nix }: let
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
deploy-rs,
|
||||||
|
systems,
|
||||||
|
treefmt-nix,
|
||||||
|
}:
|
||||||
|
let
|
||||||
# systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
|
# systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
|
||||||
forAllSystems = fn:
|
forAllSystems =
|
||||||
nixpkgs.lib.genAttrs (import systems) (system: fn nixpkgs.legacyPackages.${system});
|
fn: nixpkgs.lib.genAttrs (import systems) (system: fn nixpkgs.legacyPackages.${system});
|
||||||
|
|
||||||
treefmtEval = forAllSystems (pkgs: treefmt-nix.lib.evalModule pkgs ./treefmt.nix);
|
treefmtEval = forAllSystems (pkgs: treefmt-nix.lib.evalModule pkgs ./treefmt.nix);
|
||||||
|
|
||||||
in {
|
in
|
||||||
|
{
|
||||||
apps = forAllSystems (pkgs: {
|
apps = forAllSystems (pkgs: {
|
||||||
"deploy" = {
|
"deploy" = {
|
||||||
type = "app";
|
type = "app";
|
||||||
program = let
|
program =
|
||||||
ci = (pkgs.writeShellApplication {
|
let
|
||||||
|
ci = (
|
||||||
|
pkgs.writeShellApplication {
|
||||||
name = "ci.sh";
|
name = "ci.sh";
|
||||||
text = ''
|
text = ''
|
||||||
nix build
|
nix build
|
||||||
'';
|
'';
|
||||||
});
|
}
|
||||||
in "${ci}/ci.sh";
|
);
|
||||||
|
in
|
||||||
|
"${ci}/ci.sh";
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
packages = forAllSystems (pkgs: {
|
packages = forAllSystems (pkgs: {
|
||||||
default = pkgs.callPackage ./package.nix {};
|
default = pkgs.callPackage ./package.nix { };
|
||||||
});
|
});
|
||||||
deploy.nodes.myblog = {
|
deploy.nodes.myblog = {
|
||||||
hostname = "saji.dev";
|
hostname = "saji.dev";
|
||||||
|
|
|
@ -7,36 +7,40 @@ export default function figcaptionPlugin(md) {
|
||||||
for (let i = 0; i < tokens.length; i++) {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
// Check for paragraph containing only an image
|
// Check for paragraph containing only an image
|
||||||
if (
|
if (
|
||||||
tokens[i].type === 'paragraph_open' &&
|
tokens[i].type === "paragraph_open" &&
|
||||||
i + 2 < tokens.length &&
|
i + 2 < tokens.length &&
|
||||||
tokens[i + 1].type === 'inline' &&
|
tokens[i + 1].type === "inline" &&
|
||||||
tokens[i + 1].children &&
|
tokens[i + 1].children &&
|
||||||
tokens[i + 1].children.length === 1 &&
|
tokens[i + 1].children.length === 1 &&
|
||||||
tokens[i + 1].children[0].type === 'image' &&
|
tokens[i + 1].children[0].type === "image" &&
|
||||||
tokens[i + 2].type === 'paragraph_close'
|
tokens[i + 2].type === "paragraph_close"
|
||||||
) {
|
) {
|
||||||
// Check if the next token is a paragraph starting with emphasis
|
// Check if the next token is a paragraph starting with emphasis
|
||||||
if (
|
if (
|
||||||
i + 5 < tokens.length &&
|
i + 5 < tokens.length &&
|
||||||
tokens[i + 3].type === 'paragraph_open' &&
|
tokens[i + 3].type === "paragraph_open" &&
|
||||||
tokens[i + 4].type === 'inline' &&
|
tokens[i + 4].type === "inline" &&
|
||||||
tokens[i + 4].children &&
|
tokens[i + 4].children &&
|
||||||
tokens[i + 4].children.length > 0 &&
|
tokens[i + 4].children.length > 0 &&
|
||||||
tokens[i + 4].children[0].type === 'em_open' &&
|
tokens[i + 4].children[0].type === "em_open" &&
|
||||||
tokens[i + 5].type === 'paragraph_close'
|
tokens[i + 5].type === "paragraph_close"
|
||||||
) {
|
) {
|
||||||
figcaptionStartIndex = i + 3; // Start index of the caption paragraph
|
figcaptionStartIndex = i + 3; // Start index of the caption paragraph
|
||||||
|
|
||||||
// --- Replace tokens ---
|
// --- Replace tokens ---
|
||||||
|
|
||||||
// 1. Change paragraph_open to figure_open
|
// 1. Change paragraph_open to figure_open
|
||||||
const figureOpen = new state.Token('figure_open', 'figure', 1);
|
const figureOpen = new state.Token("figure_open", "figure", 1);
|
||||||
tokens[i] = figureOpen; // Replace paragraph_open
|
tokens[i] = figureOpen; // Replace paragraph_open
|
||||||
|
|
||||||
// 2. Keep the inline token with the image as is (tokens[i+1])
|
// 2. Keep the inline token with the image as is (tokens[i+1])
|
||||||
|
|
||||||
// 3. Change paragraph_close to figcaption_open
|
// 3. Change paragraph_close to figcaption_open
|
||||||
const figcaptionOpen = new state.Token('figcaption_open', 'figcaption', 1);
|
const figcaptionOpen = new state.Token(
|
||||||
|
"figcaption_open",
|
||||||
|
"figcaption",
|
||||||
|
1,
|
||||||
|
);
|
||||||
tokens[i + 2] = figcaptionOpen; // Replace paragraph_close
|
tokens[i + 2] = figcaptionOpen; // Replace paragraph_close
|
||||||
|
|
||||||
// 4. Remove the caption's paragraph_open
|
// 4. Remove the caption's paragraph_open
|
||||||
|
@ -45,23 +49,29 @@ export default function figcaptionPlugin(md) {
|
||||||
// 5. Modify the caption's inline content: remove outer <em> tags
|
// 5. Modify the caption's inline content: remove outer <em> tags
|
||||||
const captionInlineToken = tokens[figcaptionStartIndex]; // Now at index i+3 after splice
|
const captionInlineToken = tokens[figcaptionStartIndex]; // Now at index i+3 after splice
|
||||||
if (
|
if (
|
||||||
captionInlineToken.children[0].type === 'em_open' &&
|
captionInlineToken.children[0].type === "em_open" &&
|
||||||
captionInlineToken.children[captionInlineToken.children.length - 1].type === 'em_close'
|
captionInlineToken.children[captionInlineToken.children.length - 1]
|
||||||
|
.type === "em_close"
|
||||||
) {
|
) {
|
||||||
captionInlineToken.children.shift(); // Remove em_open
|
captionInlineToken.children.shift(); // Remove em_open
|
||||||
captionInlineToken.children.pop(); // Remove em_close
|
captionInlineToken.children.pop(); // Remove em_close
|
||||||
}
|
}
|
||||||
// Adjust level for caption content
|
// Adjust level for caption content
|
||||||
captionInlineToken.level += 1;
|
captionInlineToken.level += 1;
|
||||||
captionInlineToken.children.forEach(child => { child.level += 1; });
|
captionInlineToken.children.forEach((child) => {
|
||||||
|
child.level += 1;
|
||||||
|
});
|
||||||
|
|
||||||
// 6. Change the caption's paragraph_close to figcaption_close
|
// 6. Change the caption's paragraph_close to figcaption_close
|
||||||
const figcaptionClose = new state.Token('figcaption_close', 'figcaption', -1);
|
const figcaptionClose = new state.Token(
|
||||||
|
"figcaption_close",
|
||||||
|
"figcaption",
|
||||||
|
-1,
|
||||||
|
);
|
||||||
tokens[figcaptionStartIndex + 1] = figcaptionClose; // Replace paragraph_close (now at i+4)
|
tokens[figcaptionStartIndex + 1] = figcaptionClose; // Replace paragraph_close (now at i+4)
|
||||||
|
|
||||||
// 7. Add figure_close after figcaption_close
|
// 7. Add figure_close after figcaption_close
|
||||||
const figureClose = new state.Token('figure_close', 'figure', -1);
|
const figureClose = new state.Token("figure_close", "figure", -1);
|
||||||
tokens.splice(figcaptionStartIndex + 2, 0, figureClose); // Insert figure_close (at i+5)
|
tokens.splice(figcaptionStartIndex + 2, 0, figureClose); // Insert figure_close (at i+5)
|
||||||
|
|
||||||
// Adjust token index to skip the newly inserted/modified tokens
|
// Adjust token index to skip the newly inserted/modified tokens
|
||||||
|
@ -71,13 +81,27 @@ export default function figcaptionPlugin(md) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
md.core.ruler.after('inline', 'figcaption', figcaptionRule);
|
md.core.ruler.after("inline", "figcaption", figcaptionRule);
|
||||||
|
|
||||||
// Add renderer rules if they don't exist
|
// Add renderer rules if they don't exist
|
||||||
md.renderer.rules.figure_open = md.renderer.rules.figure_open || function () { return '<figure>\n'; };
|
md.renderer.rules.figure_open =
|
||||||
md.renderer.rules.figure_close = md.renderer.rules.figure_close || function () { return '</figure>\n'; };
|
md.renderer.rules.figure_open ||
|
||||||
md.renderer.rules.figcaption_open = md.renderer.rules.figcaption_open || function () { return '<figcaption>'; };
|
function () {
|
||||||
md.renderer.rules.figcaption_close = md.renderer.rules.figcaption_close || function () { return '</figcaption>\n'; };
|
return "<figure>\n";
|
||||||
|
};
|
||||||
|
md.renderer.rules.figure_close =
|
||||||
|
md.renderer.rules.figure_close ||
|
||||||
|
function () {
|
||||||
|
return "</figure>\n";
|
||||||
|
};
|
||||||
|
md.renderer.rules.figcaption_open =
|
||||||
|
md.renderer.rules.figcaption_open ||
|
||||||
|
function () {
|
||||||
|
return "<figcaption>";
|
||||||
|
};
|
||||||
|
md.renderer.rules.figcaption_close =
|
||||||
|
md.renderer.rules.figcaption_close ||
|
||||||
|
function () {
|
||||||
|
return "</figcaption>\n";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
const HSEP = "---";
|
const HSEP = "---";
|
||||||
const VSEP = "===";
|
const VSEP = "===";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MarkdownIt plugin to generate revealjs friendly markup.
|
* MarkdownIt plugin to generate revealjs friendly markup.
|
||||||
*
|
*
|
||||||
|
@ -29,12 +28,12 @@ export default function revealjs_plugin(md, options) {
|
||||||
function renderOpening(tokens, idx, options, env, slf) {
|
function renderOpening(tokens, idx, options, env, slf) {
|
||||||
var token = tokens[idx];
|
var token = tokens[idx];
|
||||||
return `<${tokens[idx].tag}${slf.renderAttrs(tokens[idx])}>`;
|
return `<${tokens[idx].tag}${slf.renderAttrs(tokens[idx])}>`;
|
||||||
};
|
}
|
||||||
|
|
||||||
function renderClosing(tokens, idx, options, env, slf) {
|
function renderClosing(tokens, idx, options, env, slf) {
|
||||||
var token = tokens[idx];
|
var token = tokens[idx];
|
||||||
return `</${tokens[idx].tag}>`;
|
return `</${tokens[idx].tag}>`;
|
||||||
};
|
}
|
||||||
|
|
||||||
md.renderer.rules.pres_open = renderOpening;
|
md.renderer.rules.pres_open = renderOpening;
|
||||||
md.renderer.rules.pres_close = renderClosing;
|
md.renderer.rules.pres_close = renderClosing;
|
||||||
|
@ -64,9 +63,7 @@ export default function revealjs_plugin(md, options) {
|
||||||
function presentationOpen(state) {
|
function presentationOpen(state) {
|
||||||
var token = new state.Token("pres_open", "section", 1);
|
var token = new state.Token("pres_open", "section", 1);
|
||||||
token.block = true;
|
token.block = true;
|
||||||
token.attrs = [
|
token.attrs = [["class", "reveal"]];
|
||||||
["class", "reveal"]
|
|
||||||
];
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,9 +74,7 @@ export default function revealjs_plugin(md, options) {
|
||||||
function slidesOpen(state) {
|
function slidesOpen(state) {
|
||||||
var token = new state.Token("slides_open", "div", 1);
|
var token = new state.Token("slides_open", "div", 1);
|
||||||
token.block = true;
|
token.block = true;
|
||||||
token.attrs = [
|
token.attrs = [["class", "slides"]];
|
||||||
["class", "slides"]
|
|
||||||
];
|
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +92,7 @@ export default function revealjs_plugin(md, options) {
|
||||||
return new state.Token("slide_close", "section", -1);
|
return new state.Token("slide_close", "section", -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
md.core.ruler.push("revealjs", function(state) {
|
md.core.ruler.push("revealjs", function (state) {
|
||||||
let divIdx = 0;
|
let divIdx = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
divIdx = nextDivider(state.tokens, divIdx);
|
divIdx = nextDivider(state.tokens, divIdx);
|
||||||
|
@ -123,9 +118,11 @@ export default function revealjs_plugin(md, options) {
|
||||||
// in it's own section
|
// in it's own section
|
||||||
if (openSlides === 1) {
|
if (openSlides === 1) {
|
||||||
let slideOpenIdx = previousSlideOpen(state.tokens, divIdx);
|
let slideOpenIdx = previousSlideOpen(state.tokens, divIdx);
|
||||||
state.tokens.splice(slideOpenIdx, 1,
|
state.tokens.splice(
|
||||||
|
slideOpenIdx,
|
||||||
|
1,
|
||||||
state.tokens[slideOpenIdx], // reuse it to avoid increasing openSlides
|
state.tokens[slideOpenIdx], // reuse it to avoid increasing openSlides
|
||||||
slideOpen(state)
|
slideOpen(state),
|
||||||
);
|
);
|
||||||
divIdx++; // we added a token before the divider, we need to update divIdx
|
divIdx++; // we added a token before the divider, we need to update divIdx
|
||||||
}
|
}
|
||||||
|
@ -152,4 +149,4 @@ export default function revealjs_plugin(md, options) {
|
||||||
state.tokens.push(slidesClose(state));
|
state.tokens.push(slidesClose(state));
|
||||||
state.tokens.push(presentationClose(state));
|
state.tokens.push(presentationClose(state));
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
importNpmLock,
|
importNpmLock,
|
||||||
vips,
|
vips,
|
||||||
lib,
|
lib,
|
||||||
}: buildNpmPackage {
|
}:
|
||||||
|
buildNpmPackage {
|
||||||
name = "myblog";
|
name = "myblog";
|
||||||
version = "unstable";
|
version = "unstable";
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
|
|
|
@ -1,46 +1,51 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'WO3';
|
font-family: "WO3";
|
||||||
src: url('/fonts/WO3.woff2') format('woff2'),
|
src:
|
||||||
url('/fonts/WO3.ttf') format('ttf');
|
url("/fonts/WO3.woff2") format("woff2"),
|
||||||
|
url("/fonts/WO3.ttf") format("ttf");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "wip3out";
|
font-family: "wip3out";
|
||||||
src: url('/fonts/wip3out.woff2') format('woff2'),
|
src:
|
||||||
url('/fonts/wip3out.ttf') format('ttf');
|
url("/fonts/wip3out.woff2") format("woff2"),
|
||||||
|
url("/fonts/wip3out.ttf") format("ttf");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-stretch: semi-expanded;
|
font-stretch: semi-expanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'SometypeMono';
|
font-family: "SometypeMono";
|
||||||
src: url('/fonts/SometypeMono-Regular.woff2') format('woff2'),
|
src:
|
||||||
url('/fonts/SometypeMono-Regular.ttf') format('ttf') ;
|
url("/fonts/SometypeMono-Regular.woff2") format("woff2"),
|
||||||
|
url("/fonts/SometypeMono-Regular.ttf") format("ttf");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'SometypeMono';
|
font-family: "SometypeMono";
|
||||||
src: url('/fonts/SometypeMono-Bold.woff2') format('woff2'),
|
src:
|
||||||
url('/fonts/SometypeMono-Bold.ttf') format('ttf') ;
|
url("/fonts/SometypeMono-Bold.woff2") format("woff2"),
|
||||||
|
url("/fonts/SometypeMono-Bold.ttf") format("ttf");
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'SometypeMono';
|
font-family: "SometypeMono";
|
||||||
src: url('/fonts/SometypeMono-Medium.woff2') format('woff2'),
|
src:
|
||||||
url('/fonts/SometypeMono-Medium.ttf') format('ttf') ;
|
url("/fonts/SometypeMono-Medium.woff2") format("woff2"),
|
||||||
|
url("/fonts/SometypeMono-Medium.ttf") format("ttf");
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Orbitron";
|
font-family: "Orbitron";
|
||||||
src: url('/fonts/Orbitron-VariableFont_wght.woff2') format('woff2');
|
src: url("/fonts/Orbitron-VariableFont_wght.woff2") format("woff2");
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
/* Theme colors */
|
/* Theme colors */
|
||||||
:root {
|
:root {
|
||||||
|
|
||||||
|
|
||||||
--text-color-link: var(--color-cyan);
|
--text-color-link: var(--color-cyan);
|
||||||
--text-color-link-active: var(--color-cyan-bright);
|
--text-color-link-active: var(--color-cyan-bright);
|
||||||
--text-color-link-visited: var(--color-cyan);
|
--text-color-link-visited: var(--color-cyan);
|
||||||
|
@ -18,7 +16,6 @@
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root {
|
||||||
|
|
||||||
/* --text-color is assigned to --color-gray-_ above */
|
/* --text-color is assigned to --color-gray-_ above */
|
||||||
/* --text-color-link: #1493fb; */
|
/* --text-color-link: #1493fb; */
|
||||||
/* --text-color-link-active: #6969f7; */
|
/* --text-color-link-active: #6969f7; */
|
||||||
|
@ -26,11 +23,9 @@
|
||||||
--text-color-link: var(--color-cyan);
|
--text-color-link: var(--color-cyan);
|
||||||
--text-color-link-active: var(--color-cyan-bright);
|
--text-color-link-active: var(--color-cyan-bright);
|
||||||
--text-color-link-visited: var(--color-cyan);
|
--text-color-link-visited: var(--color-cyan);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* list style custom */
|
/* list style custom */
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
|
@ -130,7 +125,7 @@ code {
|
||||||
font-family: var(--font-family-monospace);
|
font-family: var(--font-family-monospace);
|
||||||
}
|
}
|
||||||
pre:not([class*="language-"]) {
|
pre:not([class*="language-"]) {
|
||||||
margin: .5em 0;
|
margin: 0.5em 0;
|
||||||
line-height: 1.375; /* 22px /16 */
|
line-height: 1.375; /* 22px /16 */
|
||||||
-moz-tab-size: var(--syntax-tab-size);
|
-moz-tab-size: var(--syntax-tab-size);
|
||||||
-o-tab-size: var(--syntax-tab-size);
|
-o-tab-size: var(--syntax-tab-size);
|
||||||
|
@ -154,7 +149,7 @@ code {
|
||||||
/* Header */
|
/* Header */
|
||||||
header {
|
header {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1em .5em;
|
gap: 1em 0.5em;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
@ -219,8 +214,8 @@ header {
|
||||||
font-size: 1.1875em; /* 19px /16 */
|
font-size: 1.1875em; /* 19px /16 */
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
flex-basis: calc(100% - 1.5rem);
|
flex-basis: calc(100% - 1.5rem);
|
||||||
padding-left: .25em;
|
padding-left: 0.25em;
|
||||||
padding-right: .5em;
|
padding-right: 0.5em;
|
||||||
text-underline-position: from-font;
|
text-underline-position: from-font;
|
||||||
text-underline-offset: 0;
|
text-underline-offset: 0;
|
||||||
text-decoration-thickness: 1px;
|
text-decoration-thickness: 1px;
|
||||||
|
@ -245,7 +240,7 @@ header {
|
||||||
.post-metadata {
|
.post-metadata {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: .5em;
|
gap: 0.5em;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -259,7 +254,7 @@ header {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
margin-left: .1em;
|
margin-left: 0.1em;
|
||||||
}
|
}
|
||||||
a[href].header-anchor,
|
a[href].header-anchor,
|
||||||
a[href].header-anchor:visited {
|
a[href].header-anchor:visited {
|
||||||
|
@ -277,12 +272,13 @@ a[href].header-anchor:focus,
|
||||||
h2 + .header-anchor {
|
h2 + .header-anchor {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
h1, h2, h3 {
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
font-family: WO3;
|
font-family: WO3;
|
||||||
letter-spacing: .1rem;
|
letter-spacing: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* blockquote styling */
|
/* blockquote styling */
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
|
@ -299,7 +295,7 @@ blockquote p {
|
||||||
|
|
||||||
/* Top-left corner bracket */
|
/* Top-left corner bracket */
|
||||||
blockquote::before {
|
blockquote::before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0.5em; /* Adjust position */
|
top: 0.5em; /* Adjust position */
|
||||||
left: 0.5em; /* Adjust position */
|
left: 0.5em; /* Adjust position */
|
||||||
|
@ -312,7 +308,7 @@ blockquote::before {
|
||||||
|
|
||||||
/* Bottom-right corner bracket */
|
/* Bottom-right corner bracket */
|
||||||
blockquote::after {
|
blockquote::after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0.5em; /* Adjust position */
|
bottom: 0.5em; /* Adjust position */
|
||||||
right: 0.5em; /* Adjust position */
|
right: 0.5em; /* Adjust position */
|
||||||
|
@ -322,4 +318,3 @@ blockquote::after {
|
||||||
border-right: 3px solid var(--color-white); /* White border, adjust thickness */
|
border-right: 3px solid var(--color-white); /* White border, adjust thickness */
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ pre[class*="language-diff-"] {
|
||||||
.token.prefix.inserted,
|
.token.prefix.inserted,
|
||||||
.token.prefix.deleted {
|
.token.prefix.deleted {
|
||||||
width: var(--eleventy-code-padding);
|
width: var(--eleventy-code-padding);
|
||||||
background-color: rgba(0,0,0,.2);
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optional: full-width background color */
|
/* Optional: full-width background color */
|
||||||
|
|
Loading…
Reference in a new issue