Compare commits
13 Commits
margin-rew
...
65645346a2
| Author | SHA1 | Date | |
|---|---|---|---|
| 65645346a2 | |||
| cb65e89e53 | |||
| 6a2fec8ef4 | |||
| aa59c90810 | |||
| 2b317930a0 | |||
| e7d56dd4bd | |||
| a4fedb276d | |||
| 277c0a2ce6 | |||
| ef3c61e9e6 | |||
| 1908126607 | |||
| 2d77f8489f | |||
| 0371651fdd | |||
| 01734d24f7 |
@@ -5,3 +5,9 @@ theme = "vanilla"
|
||||
pygmentsCodeFences = true
|
||||
pygmentsStyle = "github"
|
||||
summaryLength = 20
|
||||
|
||||
[markup]
|
||||
[markup.tableOfContents]
|
||||
endLevel = 4
|
||||
ordered = false
|
||||
startLevel = 3
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
title: About
|
||||
---
|
||||
I'm Daniel, a Computer Science student currently in my third (and final) undergraduate year at Oregon State University.
|
||||
Due my initial interest in calculators and compilers, I got involved in the Programming Language Theory research
|
||||
I'm Daniel, a Computer Science student currently working towards my Master's Degree at Oregon State University.
|
||||
Due to my initial interest in calculators and compilers, I got involved in the Programming Language Theory research
|
||||
group, gaining same experience in formal verification, domain specific language, and explainable computing.
|
||||
|
||||
For work, school, and hobby projects, I use a variety of programming languages, most commonly C/C++,
|
||||
|
||||
280
content/blog/backend_math_rendering.md
Normal file
@@ -0,0 +1,280 @@
|
||||
---
|
||||
title: Rendering Mathematics On The Back End
|
||||
date: 2020-07-15T15:27:19-07:00
|
||||
draft: true
|
||||
tags: ["Website", "Nix", "Ruby", "KaTeX", "Hugo"]
|
||||
---
|
||||
|
||||
Due to something of a streak of bad luck when it came to computers, I spent a
|
||||
significant amount of time using a Linux-based Chromebook, and then a
|
||||
Pinebook Pro. It was, in some way, enlightening. The things that I used to take
|
||||
for granted with a 'powerful' machine now became a rare luxury: StackOverflow,
|
||||
and other relatively static websites, took upwards of ten seconds to finish
|
||||
loading. On Slack, each of my keypresses could take longer than 500ms to
|
||||
appear on the screen, and sometimes, it would take several seconds. Some
|
||||
websites would present me with a white screen, and remain that way for much
|
||||
longer than I had time to wait. It was awful.
|
||||
|
||||
At one point, I installed uMatrix, and made it the default policy to block
|
||||
all JavaScript. For the most part, this worked well. Of course, I had to
|
||||
enable JavaScript for applications that needed to be interactive, like
|
||||
Slack, and Discord. But for the most part, I was able to browse the majority
|
||||
of the websites I normally browse. This went on until I started working
|
||||
on the [compiler series]({{< relref "00_compiler_intro.md" >}}) again,
|
||||
and discovered that the LaTeX math on my page, which was required
|
||||
for displaying things like inference rules, didn't work without
|
||||
JavaScript. I was left with two options:
|
||||
|
||||
* Allow JavaScript, and continue using MathJax to render my math.
|
||||
* Make it so that the mathematics is rendered on the back end.
|
||||
|
||||
I've [previously written about math rendering]({{< relref "math_rendering_is_wrong.md" >}}),
|
||||
and made the observation that MathJax's output for LaTeX is __identical__
|
||||
on every computer. From the MathJax 2.6 change log:
|
||||
|
||||
> _Improved CommonHTML output_. The CommonHTML output now provides the same layout quality and MathML support as the HTML-CSS and SVG output. It is on average 40% faster than the other outputs and the markup it produces are identical on all browsers and thus can also be pre-generated on the server via MathJax-node.
|
||||
|
||||
It seems absurd, then, to offload this kind of work into the users, to
|
||||
be done over and over again. As should be clear from the title of
|
||||
this post, this made me settle for the second option: it was
|
||||
__obviously within reach__, especially for a statically-generated website
|
||||
like mine, to render math on the backend.
|
||||
|
||||
I settled on the following architecture:
|
||||
|
||||
* As before I would generate my pages using Hugo.
|
||||
* I would use the KaTeX NPM package to rendering math.
|
||||
* To build the website no matter what computer I was on, I would use Nix.
|
||||
|
||||
It so happens that Nix isn't really required for using my approach in general.
|
||||
I will give my setup here, but feel free to skip ahead.
|
||||
|
||||
### Setting Up A Nix Build
|
||||
My `default.nix` file looks like this:
|
||||
|
||||
```Nix {linenos=table}
|
||||
{ stdenv, hugo, fetchgit, pkgs, nodejs, ruby }:
|
||||
|
||||
let
|
||||
url = "https://dev.danilafe.com/Web-Projects/blog-static.git";
|
||||
rev = "<commit>";
|
||||
sha256 = "<hash>";
|
||||
requiredPackages = import ./required-packages.nix {
|
||||
inherit pkgs nodejs;
|
||||
};
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
name = "blog-static";
|
||||
version = rev;
|
||||
src = fetchgit {
|
||||
inherit url rev sha256;
|
||||
};
|
||||
builder = ./builder.sh;
|
||||
converter = ./convert.rb;
|
||||
buildInputs = [
|
||||
hugo
|
||||
requiredPackages.katex
|
||||
(ruby.withPackages (ps: [ ps.nokogiri ]))
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
I'm using `node2nix` to generate the `required-packages.nix` file, which allows me,
|
||||
even from a sandboxed Nix build, to download and install `npm` packages. This is needed
|
||||
so that I have access to the `katex` binary at build time. I fed the following JSON file
|
||||
to `node2nix`:
|
||||
|
||||
```JSON {linenos=table}
|
||||
[
|
||||
"katex"
|
||||
]
|
||||
```
|
||||
|
||||
The Ruby script I wrote for this (more on that soon) required the `nokigiri` gem, which
|
||||
I used for traversing the HTML generated for my site. Hugo was obviously required to
|
||||
generate the HTML.
|
||||
|
||||
### Converting LaTeX To HTML
|
||||
After my first post complaining about the state of mathematics on the web, I received
|
||||
the following email (which the author allowed me to share):
|
||||
|
||||
> Sorry for having a random stranger email you, but in your blog post
|
||||
[(link)](https://danilafe.com/blog/math_rendering_is_wrong) you seem to focus on MathJax's
|
||||
difficulty in rendering things server-side, while quietly ignoring that KaTeX's front
|
||||
page advertises server-side rendering. Their documentation [(link)](https://katex.org/docs/options.html)
|
||||
even shows (at least as of the time this email was sent) that it renders both HTML
|
||||
(to be arranged nicely with their CSS) for visuals and MathML for accessibility.
|
||||
|
||||
This is a great point, and KaTeX is indeed usable for server-side rendering. But I've
|
||||
seen few people who do actually use it. Unfortunately, as I pointed out in my previous post on the subject,
|
||||
few tools remain that provide the software that actually takes your HTML page and substitutes
|
||||
LaTeX for math.
|
||||
|
||||
> [In MathJax,] The bigger issue, though, was that the `page2html`
|
||||
program, which rendered all the mathematics in a single HTML page,
|
||||
was gone. I found `tex2html` and `text2htmlcss`, which could only
|
||||
render equations without the surrounding HTML. I also found `mjpage`,
|
||||
which replaced mathematical expressions in a page with their SVG forms.
|
||||
|
||||
This is still the case, in both MathJax and KaTeX. The ability
|
||||
to render math in one step is the main selling point of front-end LaTeX renderers:
|
||||
all you have to do is drop in a file from a CDN, and voila, you have your
|
||||
math. There are no such easy answers for back-end rendering.
|
||||
|
||||
So what _do_ I do? Well, there are two types on my website: inline math and display math.
|
||||
On the command line ([here are the docs](https://katex.org/docs/cli.html)),
|
||||
the distinction is made using the `--display-mode` argument. So, the general algorithm
|
||||
is to replace the code inside the `$$...$$` with their display-rendered version,
|
||||
and the code inside the `\(...\)` with the inline-rendered version. I came up with
|
||||
the following Ruby function:
|
||||
|
||||
```Ruby {linenos=table}
|
||||
def render_cached(cache, command, string, render_comment = nil)
|
||||
cache.fetch(string) do |new|
|
||||
puts " Rendering #{render_comment || new}"
|
||||
cache[string] = Open3.popen3(command) do |i, o, e, t|
|
||||
i.write new
|
||||
i.close
|
||||
o.read.force_encoding(Encoding::UTF_8).strip
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Here, the `cache` argument is used to prevent re-running the `katex` command
|
||||
on an equation that was already rendered before (the output is the same, after all).
|
||||
The `command` is the specific shell command that we want to invoke; this would
|
||||
be either `katex` or `katex -d`. The `string` is the math equation to render,
|
||||
and the `render_comment` is the string to print to the console instead of the equation
|
||||
(so that long, display math equations are not printed out to standard out).
|
||||
|
||||
Then, given a substring of the HTML file, we use regular expressions
|
||||
to find the `\(...\)` and `$$...$$`s, and use the `render_cached` method
|
||||
on the LaTeX code inside.
|
||||
|
||||
```Ruby {linenos=table}
|
||||
def perform_katex_sub(inline_cache, display_cache, content)
|
||||
rendered = content.gsub /\\\(((?:[^\\]|\\[^\)])*)\\\)/ do |match|
|
||||
render_cached(inline_cache, "katex", $~[1])
|
||||
end
|
||||
rendered = rendered.gsub /\$\$((?:[^\$]|$[^\$])*)\$\$/ do |match|
|
||||
render_cached(display_cache, "katex -d", $~[1], "display")
|
||||
end
|
||||
return rendered
|
||||
end
|
||||
```
|
||||
|
||||
There's a bit of a trick to the final layer of this script. We want to be
|
||||
really careful about where we replace LaTeX, and where we don't. In
|
||||
particular, we _don't_ want to go into the `code` tags. Otherwise,
|
||||
it wouldn't be able to talk about LaTeX code! Thus, we can't just
|
||||
search-and-replace over the entire HTML document; we need to be context
|
||||
aware. This is where `nokigiri` comes in. We parse the HTML, and iterate
|
||||
over all of the 'text' nodes, calling `perform_katex_sub` on all
|
||||
of those that _aren't_ inside code tags.
|
||||
|
||||
Fortunately, this is pretty easy to specify thanks to something called XPath.
|
||||
This was my first time encountering it, but it seems extremely useful: it's
|
||||
a sort of language for selecting XML nodes. First, you provide an 'axis',
|
||||
which is used to specify the positions of the nodes you want to look at
|
||||
relative to the root node. The axis `/` looks at the immediate children
|
||||
(this would be the `html` tag in a properly formatted document, I would imagine).
|
||||
The axis `//` looks at all the transitive children. That is, it will look at the
|
||||
children of the root, then its children, and so on. There's also the `self` axis,
|
||||
which looks at the node itself.
|
||||
|
||||
After you provide an axis, you need to specify the type of node that you want to
|
||||
select. We can write `code`, for instance, to pick only the `<code>....</code>` tags
|
||||
from the axis we've chosen. We can also use `*` to select any node, and we can
|
||||
use `text()` to select text nodes, such as the `Hello` inside of `<b>Hello</b>`.
|
||||
|
||||
We can also apply some more conditions to the nodes we pick using `[]`.
|
||||
For us, the relevant feature here is `not(...)`, which allows us to
|
||||
select nodes that do __not__ match a particular condition. This is all
|
||||
we need to know.
|
||||
|
||||
We write:
|
||||
|
||||
* `//`, starting to search for nodes everywhere, not just the root of the document.
|
||||
* `*`, to match _any_ node. We want to replace math inside of `div`s, `span`s, `nav`s,
|
||||
all of the `h`s, and so on.
|
||||
* `[not(self::code)]` cutting out all the `code` tags.
|
||||
* `/`, now selecting the nodes that are immediate descendants of the nodes we've selected.
|
||||
* `text()`, giving us the text contents of all the nodes we've selected.
|
||||
|
||||
All in all:
|
||||
|
||||
```
|
||||
//*[not(self::code)]/text()
|
||||
```
|
||||
|
||||
Finally, we use this XPath from `nokigiri`:
|
||||
|
||||
```Ruby {linenos=table}
|
||||
files = ARGV[0..-1]
|
||||
inline_cache, display_cache = {}, {}
|
||||
|
||||
files.each do |file|
|
||||
puts "Rendering file: #{file}"
|
||||
document = Nokogiri::HTML.parse(File.open(file))
|
||||
document.search('//*[not(self::code)]/text()').each do |t|
|
||||
t.replace(perform_katex_sub(inline_cache, display_cache, t.content))
|
||||
end
|
||||
File.write(file, document.to_html)
|
||||
end
|
||||
```
|
||||
|
||||
I named this script `convert.rb`; it's used from inside of the Nix expression
|
||||
and its builder, which we will cover below.
|
||||
|
||||
### Tying it All Together
|
||||
Finally, I wanted an end-to-end script to generate HTML pages and render the LaTeX in them.
|
||||
I used Nix for this, but the below script will largely be compatible with a non-Nix system.
|
||||
I came up with the following, commenting on Nix-specific commands:
|
||||
|
||||
```Bash {linenos=table}
|
||||
source $stdenv/setup # Nix-specific; set up paths.
|
||||
|
||||
# Build site with Hugo
|
||||
# The cp is Nix-specific; it copies the blog source into the current directory.
|
||||
cp -r $src/* .
|
||||
hugo --baseUrl="https://danilafe.com"
|
||||
|
||||
# Render math in HTML and XML files.
|
||||
# $converter is Nix-specific; you can just use convert.rb.
|
||||
find public/ -regex "public/.*\.html" | xargs ruby $converter
|
||||
|
||||
# Output result
|
||||
# $out is Nix-specific; you can replace it with your destination folder.
|
||||
mkdir $out
|
||||
cp -r public/* $out/
|
||||
```
|
||||
|
||||
This is it! Using the two scripts, `convert.rb` and `builder.sh`, I
|
||||
was able to generate my blog with the math rendered on the back-end.
|
||||
Please note, though, that I had to add the KaTeX CSS to my website's
|
||||
`<head>`.
|
||||
|
||||
### Caveats
|
||||
The main caveat of my approach is performance. For every piece of
|
||||
mathematics that I render, I invoke the `katex` command. This incurs
|
||||
the penalty of Node's startup time, every time, and makes my approach
|
||||
take a few dozen seconds to run on my relatively small site. The
|
||||
better approach would be to use a NodeJS script, rather than a Ruby one,
|
||||
to perform the conversion. KaTeX also provides an API, so such a NodeJS
|
||||
script can find the files, parse the HTML, and perform the substitutions.
|
||||
I did quite like using `nokigiri` here, though, and I hope that an equivalently
|
||||
pleasant solution exists in JavaScript.
|
||||
|
||||
Re-rendering the whole website is also pretty wasteful. I rarely change the
|
||||
mathematics on more than one page at a time, but every time I do so, I have
|
||||
to re-run the script, and therefore re-render every page. This makes sense
|
||||
for me, since I use Nix, and my builds are pretty much always performed
|
||||
from scratch. On the other hand, for others, this may not be the best solution.
|
||||
|
||||
### Conclusion
|
||||
With the removal of MathJax from my site, it is now completely JavaScript free,
|
||||
and contains virtually the same HTML that it did beforehand. This, I hope,
|
||||
makes it work better on devices where computational power is more limited.
|
||||
I also hope that it illustrates a general principle - it's very possible,
|
||||
and plausible, to render LaTeX on the back-end for a static site.
|
||||
BIN
content/blog/dell_is_horrible/brokenkey.jpg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
content/blog/dell_is_horrible/brokenlcd.jpg
Normal file
|
After Width: | Height: | Size: 476 KiB |
BIN
content/blog/dell_is_horrible/dm_1.png
Normal file
|
After Width: | Height: | Size: 158 KiB |
BIN
content/blog/dell_is_horrible/dm_2.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
content/blog/dell_is_horrible/dm_3.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
content/blog/dell_is_horrible/dm_4.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
content/blog/dell_is_horrible/dm_5.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
384
content/blog/dell_is_horrible/index.md
Normal file
@@ -0,0 +1,384 @@
|
||||
---
|
||||
title: DELL Is A Horrible Company And You Should Avoid Them At All Costs
|
||||
date: 2020-07-17T16:23:34-07:00
|
||||
draft: true
|
||||
tags: ["Electronics"]
|
||||
---
|
||||
|
||||
I really do not want this to be a consumer electronics blog. Such things
|
||||
aren't interesting to me, and nor do I have much knowledge
|
||||
about them. However, sometimes, ripples from these areas make their way
|
||||
into my life, and this is one such instance. Let me tell you
|
||||
{{< sidenote "right" "source-note" "a story" >}}
|
||||
I originally wrote about this in
|
||||
<a href="https://www.dell.com/community/XPS/Ridiculously-Bad-Support-Experience/td-p/7554383">a thread on DELL's support website</a>. Some of this post is
|
||||
going to be adapted from the support website, but some things have happened
|
||||
since. You will probably notice the change between the terse language I used
|
||||
in the original post and the fresh text that I'm writing now.
|
||||
{{< /sidenote >}} of
|
||||
my experience with DELL and their XPS 2-in-1 laptop, which has gone on since
|
||||
around January of 2020, and is still going at the time of writing, in July
|
||||
2020, half a year later.
|
||||
|
||||
I was, until recently, an undergraduate student in Computer Science. I will
|
||||
soon be starting my Masters in Computer Science, too. I say this to make one
|
||||
thing clear: I need a computer. Not only is it a necessity for my major,
|
||||
but the majority of my hobbies -- including this blog -- are digital, too.
|
||||
Since my university is a couple of hours from my home, I travel back and forth
|
||||
a lot. I also have a cozy little spot in the
|
||||
{{< sidenote "right" "offices-note" "graduate student offices" >}}
|
||||
They're a bunch of cubicles in a keycard-protected room, really. Nothing fancy.
|
||||
{{< /sidenote >}}at my university, but travel by bus, so I find myself spending
|
||||
roughly equal portions of my work time at home and 'elsewhere'. A laptop
|
||||
as my primary machine, I thought, made sense. But it had to be a decent one.
|
||||
Persuaded by one of my instructors, who stressed the importance of vision and
|
||||
a decent screen, I settled on a DELL XPS, which at the time came with a 4k
|
||||
display.
|
||||
|
||||
As is commonplace, things went great at first. The screen _was_ really nice,
|
||||
all of my code compiled swiftly, and even the games I occasionally played ran
|
||||
at a solid 60fps. I was happy with my purchase.
|
||||
|
||||
There was one hiccup before things went really downhill, a sort of
|
||||
foreshadowing of things to come. My trackpad didn't work at peculiar times.
|
||||
|
||||
### Prologue: Trackpad Hiccups
|
||||
While working, booted into Linux, I noticed that my trackpad was having some
|
||||
trouble. It was stuttering, and occasionally wouldn't work at all for seconds
|
||||
at a time. I assumed that this was a problem with the trackpad drivers on
|
||||
Linux, or perhaps the whole system was freezing up. I rebooted, and the
|
||||
problem went away.
|
||||
|
||||
Until it came back.
|
||||
|
||||
A few days later, my trackpad was freezing virtually every minute.
|
||||
It was strange, but fortunately, I'm used to a keyboard-based workflow, and
|
||||
the malfunctions did not affect me too much. It was just a little troubling.
|
||||
What soon made it more troubling, was that I noticed this exact same issue
|
||||
occurring on Windows. To me, this meant one dreadful thing: it was a hardware
|
||||
issue.
|
||||
|
||||
I poked and prodded for a little bit, and finally discovered the cause:
|
||||
whenever I put my hand on the left palmrest, the trackpad would reliably stop
|
||||
working. Knowing what the issue was, I called DELL. I spoke to a guy on the
|
||||
other end, who had me run through diagnostics, driver updates, and BIOS
|
||||
settings (I imagined this was procedure, so I didn't mind doing the extra
|
||||
work to make the other guy's job easier). Finally, he scheduled a repair
|
||||
appointment. A technician came into my house, took off the laptop cover,
|
||||
and said something along the lines of:
|
||||
|
||||
> Now look. They gave me a whole new motherboard and case to replace yours,
|
||||
but in my personal opinion, this is a bad idea. Things are bound to break
|
||||
when you do this. See how the replacement case has an insulating piece
|
||||
of fabric under the left palmrest, and yours doesn't? Why don't we rip
|
||||
the fabric off the replacement case, and tape it in place on your machine,
|
||||
without any reassembly?
|
||||
|
||||
This man was wiser than any of the other DELL technicians, I now understand.
|
||||
The repair went without a hitch. He grilled me for going to college instead of
|
||||
just picking up a trade, which was cheaper and offered more job security.
|
||||
In the end, I felt a little weird about having a piece of fabric duct taped
|
||||
inside my computer, but the trackpad had no more issues ever since. All was
|
||||
well.
|
||||
|
||||
### Service Request 1: Broken D Key
|
||||
All was well, that is, until the middle of winter term. I was typing up an
|
||||
assignment for a university class. I was working as usual, when I suddenly
|
||||
noticed that the "d" key stopped working - it had to be pressed rather weird
|
||||
to register on the computer. I looked down, and discovered that the key had
|
||||
snapped in half. The top part of the key fell off shortly thereafter.
|
||||
|
||||
{{< figure src="brokenkey.jpg" caption="The broken D key shortly after the above events." >}}
|
||||
|
||||
At that point, I was more surprised than anything. I hadn't heard of something
|
||||
like this ever happening, especially under circumstances as normal as typing.
|
||||
Regardless, I contacted support, and set up a repair appointment. Things only
|
||||
went downhill from there.
|
||||
|
||||
Again, the appointment was scheduled, and only a few days later, another
|
||||
technician arrived at my house. The only way to repair the key, he said,
|
||||
was to replace the whole keyboard. They keyboard happens to be located
|
||||
underneath all the other hardware, and so, the entire laptop had to be
|
||||
disassembled and reassembled from scratch. He worked for about an hour, and
|
||||
eventually, he put the machine together. The words of the previous
|
||||
technician, who wanted to avoid doing exactly what had just been done, echoed
|
||||
in my head:
|
||||
|
||||
> Things are bound to break when you do this.
|
||||
|
||||
I asked him to test it, just to make sure everything works. Sure enough,
|
||||
not everything did work: the machine no longer had sound!
|
||||
|
||||
### Service Request 2: No sound
|
||||
During diagnostics, the laptop did not emit the "beep" it usually does. This
|
||||
was the first sign. Booting into Windows, the sound icon was crossed out in
|
||||
red, and no sound was present. Booting into Linux led to similar results.
|
||||
The microphone on the machine did not seem to work either. The service
|
||||
technician said that he didn't have the parts to repair it, told me he'd call
|
||||
it in, and left. Soon after, I got an email asking for times I'm available to
|
||||
call: I said "any time except for 1-4 pacific time". DELL support proceeded
|
||||
to call me at 3pm pacific time, when I had no service. Unable to reach me,
|
||||
they promptly notified me that they are archiving my service request.
|
||||
|
||||
This all occurred near finals week at my university, so I had to put the issue
|
||||
on hold. I had to maintain my grades, and I had to grade heaps of assignments
|
||||
from other students. Though the lack of sound was annoying, it wasn't as
|
||||
pressing as preparing for exams, so it was during spring break that I finally
|
||||
called again, and scheduled the service appointment. By then,
|
||||
{{< sidenote "right" "pandemic-note" "the pandemic was in full swing," >}}
|
||||
Just for posterity, in 2020, there had been an outbreak of COVID-19,
|
||||
a Coronavirus. Many states in the U.S., including my own, issued
|
||||
the orders for lockdown and social distancing, which meant the closing
|
||||
of schools, restaurants, and, apparently, the cessation of in-person
|
||||
repairs.
|
||||
{{< /sidenote >}}and DELL told me they'd mail me a box to put my laptop in, and
|
||||
I'd have to mail it off to their service center. Sure, I thought, that's
|
||||
fine. If it's at the service center, they won't ever "not have the required
|
||||
parts". I told the tech support person my address, he read it back to me, and
|
||||
so it was settled.
|
||||
|
||||
Until, that is, the box arrived at the wrong address.
|
||||
|
||||
I had received the machine as a gift from my family, who purchased the
|
||||
computer to arrive at their address. The box arrived at that address too,
|
||||
despite my explicit instructions to have it deliver to my current residence.
|
||||
Since my family and I live 2 hours apart, it took 4 total hours to get the box
|
||||
to me (a drive that couldn't be made right away!), and by the time I had it,
|
||||
DELL was already threatening me again with closing the service request.
|
||||
Eventually, I was able to mail the machine off, and about 5 business days
|
||||
later (business days during which I did not have a working machine, which is
|
||||
very necessary for my school and job) I received it back. I was excited to
|
||||
have the machine back, but that didn't last very long. As I was using the
|
||||
computer with Wolfram Mathematica (a rather heavy piece of software running
|
||||
under Linux), I noticed that it was discharging even while plugged in. I
|
||||
booted into Windows, and was greeted with a warning, something along the
|
||||
lines of: "you are using a slow charger. Please use the official adapter".
|
||||
But I was using the official adapter! I also tried to plug my mouse into the
|
||||
relevant USB-C port, only to discover that it did not work. I had to make
|
||||
another service requests.
|
||||
|
||||
### Service Request 3: Broken Charging Port
|
||||
This time, I made sure to tell the person on the other end of the support
|
||||
call to please send it to my address. I asked if there was anything I can do,
|
||||
or anyone I can contact, and was told "no, just mail the computer in again."
|
||||
I obliged. The box arrived at the right address this time, so I was able to
|
||||
ship it off.
|
||||
|
||||
In the "describe your issue" field on the provided form, I begged the
|
||||
technicians to send me a working machine. "Please", I wrote "Last time I got
|
||||
a machine back from support, it was still broken. I really need it for school
|
||||
and work!". 5 business days later, I received the machine back. I plugged it
|
||||
in to make sure it worked, only to find out . . . that the very same charging
|
||||
port that I requested be repaired, is still broken! It would've been funny,
|
||||
if it wasn't infuriating. How is it possible for me to receive a machine from
|
||||
repairs, without the thing I asked to repair being as much as improved?!
|
||||
|
||||
Worse, a day after I received the machine back (I was able to keep using it
|
||||
thanks to it having two USB-C ports capable of charging), the LCD suddenly
|
||||
flashed, and started flickering. Thinking it was a software glitch, I
|
||||
restarted the machine, only to discover the same flickering during the boot
|
||||
animation and menu. Not only was the charging port not repaired, but now my
|
||||
LCD was broken! (in the below picture, the screen is meant to be blue, but
|
||||
the bottom part of the display is purple and flickering).
|
||||
|
||||
{{< figure src="brokenlcd.jpg" caption="The broken LCD." >}}
|
||||
|
||||
### Service Request 4: Broken LCD
|
||||
I called in to support again, and they once again told me to ship the machine
|
||||
off. What's worse, they accused me of breaking the port myself, and told me
|
||||
this was no longer covered under basic warranty. I had to explain all over
|
||||
again that the port worked fine before the fateful day the D-key snapped. They
|
||||
told me they'd "look into it". Eventually, I received a box in the mail. I
|
||||
wasn't told I would be receiving a box, but that wasn't a big deal. I mailed
|
||||
off the machine.
|
||||
|
||||
The UPS shipping was always the most streamlined part of the process. A day
|
||||
later, I was told my machine was received intact. Another day, and I was
|
||||
informed that the technicians are starting to work on it. And then,
|
||||
a few hours later:
|
||||
|
||||
> __Current Status:__
|
||||
> The part(s) needed to repair your system are not currently in stock.
|
||||
> __What's Next:__
|
||||
> In most cases the parts are available is less than five days.
|
||||
|
||||
A few days is no big deal, and it made sense that DELL wouldn't just
|
||||
have screens lying around. So I waited. And waited. And waited. Two weeks
|
||||
later, I got a little tired of waiting, and called the repair center.
|
||||
An automated message told me:
|
||||
|
||||
> We're currently experiencing heavy call volumes. Please try again later. Goodbye.
|
||||
|
||||
And the call was dropped. This happened every time I tried to call, no matter
|
||||
the hour. The original status update -- the one that notified me about the
|
||||
part shortage -- came on May 8th, but the machine finally arrived to me
|
||||
(without prior warning) on June 2nd, almost a month later.
|
||||
|
||||
The charging port worked. Sound
|
||||
worked. The screen wasn't flickering. I was happy for the brief moments that
|
||||
my computer was loading. As soon as I started vim, though, I noticed something
|
||||
was off: the fonts looked more pixelated. The DPI settings I'd painstakingly
|
||||
tweaked were wrong. Now that I thought about it, even the GRUB menu was
|
||||
larger. My suspicion growing, I booted into Windows, and looked at the display
|
||||
settings. Noticeably fewer resolutions were listed in the drop-down menu;
|
||||
worse, the highest resolution was 1080p. After almost a month of waiting,
|
||||
DELL replaced my 4k laptop display with a 1080p one.
|
||||
|
||||
### System Replacement: Worse LCD Screen
|
||||
|
||||
I admit, I was angry. At the same time, the absurdity of it all was also
|
||||
unbearable. Was this constant loop of hardware damage, the endless number of
|
||||
support calls filled with hoarse jazz music, part of some kind of Kafkaesque
|
||||
dream? I didn't know. I was at the end of my wits as to what to do. As a last
|
||||
resort, I made a tweet from my almost-abandoned account. DELL Support's Twitter
|
||||
account quickly responded, eager as always to destroy any semblance of
|
||||
transparency by switching to private messages:
|
||||
|
||||
{{< tweet 1268064691416334344 >}}
|
||||
|
||||
I let them know my thoughts on the matter. I wanted a new machine.
|
||||
|
||||
{{< figure src="dm_1.png" caption="The first real exchange between me and DELL support." >}}
|
||||
|
||||
Of course we can proceed further. I wanted to know what kind of machine I was getting,
|
||||
though. As long as it was the same model that I originally bought,
|
||||
{{< sidenote "right" "replacement-note" "it would be better than what I have." >}}
|
||||
At least in principle, it would be. Perhaps the wear and tear on the replacement
|
||||
parts would be greater, but at least I would have, presumably, a machine
|
||||
in good condition that had the 4k screen that made me buy it in the first place.
|
||||
{{< /sidenote >}}
|
||||
Despite this, I knew that the machine I was getting was likely refurbished.
|
||||
This _had_ to mean that some of the parts would come from other, used, machines.
|
||||
This irked me, because, well, I payed for a new machine.
|
||||
|
||||
{{< figure src="dm_2.png" caption="Ah, the classic use of canned responses." >}}
|
||||
|
||||
Their use of the canned response, and their unwillingness to answer this simple
|
||||
question, was transparent. Indeed, the machine would be made of used
|
||||
parts. I still wanted to proceed. DELL requested that I sent an image of
|
||||
my machine which included its service tag, together with a piece of
|
||||
paper which included my name and email address. I obliged, and quickly got a response:
|
||||
|
||||
{{< figure src="dm_3.png" caption="If it was me who was silent for 4 days, my request would've long been cancelled. " >}}
|
||||
|
||||
Thanks, Kalpana. Try to remember that name; you will never hear it again, not in this post.
|
||||
About a week later, I get the following beauty:
|
||||
|
||||
{{< figure src="dm_4.png" caption="Excuse me? What's going on?" >}}
|
||||
|
||||
My initial request was cancelled? Why wasn't I told? What was the reason?
|
||||
What the heck was going on at DELL Support? Should I be worried?
|
||||
My question of "Why" was answered with the apt response of "Yes",
|
||||
and a message meant to pacify me. While this was going on, I ordered
|
||||
a
|
||||
{{< sidenote "right" "pinebook-note" "Pinebook Pro." >}}
|
||||
The Pinebook – a $200 machine – has, thus far, worked more reliably than any DELL product
|
||||
I've had the misfortune of owning.
|
||||
{{< /sidenote >}} It was not a replacement for the DELL machine, but rather
|
||||
the first step towards migrating my setup to a stationary computer,
|
||||
and a small, lightweight SSH device. At this point,
|
||||
there was no more faith in DELL left in my mind.
|
||||
|
||||
Soon, DELL required my attention, only to tell me that they put in
|
||||
a request to see that status of my request. How bureaucratic. Two
|
||||
more names -- Kareem and JKC -- flickered through the chats,
|
||||
also never to be seen again.
|
||||
|
||||
{{< figure src="dm_5.png" caption="Not much of a conversation, really." >}}
|
||||
|
||||
Finally, on July 9th (a month and six days after my first real message to DELL
|
||||
support), I was notified by my roommates that FedEx tried to deliver a package
|
||||
to our house, but gave up when no one came to sign for it. On one hand, this
|
||||
is great: FedEx didn't just leave my laptop on the porch. On the other hand,
|
||||
though, this was the first time I heard about receiving the machine. I got
|
||||
to the house the next day, unpacked the new computer, and tested all the things
|
||||
that had, at one point, failed. Everything seemed to work. I transfered all my
|
||||
files, wiped the old computer clean, and mailed it off. I also spent some
|
||||
time dealing with the fallout of DELL PremierColor starting on its own,
|
||||
and permanently altering the color profile of my display. I don't have the
|
||||
special, physical calibration device, and therefore still suspect that my
|
||||
screen is somewhat green.
|
||||
|
||||
Today, I discovered that the microphone of the replacement machine didn't work.
|
||||
|
||||
### Am I The Problem?
|
||||
When the mysterious FedEx package arrived at my door on July 9th, I did some
|
||||
digging to verify my suspicion that it was from DELL. I discovered their
|
||||
HQ in Lebanon, TN. This gave me an opportunity to
|
||||
{{< sidenote "right" "reviews-note" "see" >}}
|
||||
See, of course, modulo whatever bias arises when only those who feel strongly leave reviews.
|
||||
{{< /sidenote >}} whether or not I was alone in this situation. I was genuinely
|
||||
worried that I was suffering from the technical variant of
|
||||
[Munchausen Syndrome](https://www.webmd.com/mental-health/munchausen-syndrome#1),
|
||||
and that I was compulsively breaking my electronics. These worries were
|
||||
dispelled by the reviews on Google:
|
||||
|
||||
{{< figure src="reviews_1.png" caption="Most of the reviews are pretty terse, but the ratings convey the general idea." >}}
|
||||
|
||||
There were even some that were shockingly similar in terms of the apparent
|
||||
incompetence of the DELL technicians:
|
||||
|
||||
{{< figure src="reviews_2.png" caption="Now, now, Maggie, I wouldn't go as far as recommending Apple." >}}
|
||||
|
||||
So, this is not uncommon. This is how DELL deals with customers now. It's
|
||||
awfully tiring, really; I've been in and out of repairs continuously for
|
||||
almost half a year, now. That's 2.5% of my life at the time of writing,
|
||||
all non-stop since the D-key. And these people probably have spent considerable
|
||||
amounts of time, too.
|
||||
|
||||
### It's About the Principle
|
||||
The microphone on my machine is rather inconsequential to me. I can, and regularly do,
|
||||
teleconference from my phone (a habit that I developed thanks to DELL, since
|
||||
my computer was so often unavailable). I don't need to dictate anything. Most
|
||||
of my communication is via chat.
|
||||
|
||||
Really, compared to the other issues (keyboard, sound, charging, USB ports, the broken or low-resolution screen)
|
||||
the microphone is a benign problem. As I have now learned, things could be worse.
|
||||
|
||||
But why should the thought, _"It could be worse"_, even cross my mind
|
||||
when dealing with such a matter? Virtually every issue that has
|
||||
occurred with my computer thus far could -- should! -- have been diagnosed
|
||||
at the repair center. The 'slow charger' warning shows up in BIOS,
|
||||
so just turning the computer on while plugged in should make it obvious something
|
||||
is wrong; doubly so when the very reason that the laptop was in repairs
|
||||
in the first place was because of the faulty charger. I refuse to believe
|
||||
that screens with different resolutions have the same part identifier,
|
||||
either. How have the standards of service from DELL fallen so low?
|
||||
How come this absurd scenario plays out not just for me, but
|
||||
for others as well? It would be comforting, in a way, to think
|
||||
that I was just the 'exceptional case'. But apparently, I'm not.
|
||||
This is standard practice.
|
||||
|
||||
### Tl;DR
|
||||
Here are he problems I've had with DELL:
|
||||
|
||||
* The machine shipped, apparently, with a missing piece of insulation.
|
||||
* The "D" key on the keyboard snapped after only a few months of use.
|
||||
* While repairing the "D" key, the DELL technician broke the computer's sound and microphone.
|
||||
* While repairing the sound and microphone, the DELL technicians broke a charging port.
|
||||
* The DELL technicians failed to repair the charging port, mailing me back a machine
|
||||
exhibiting the same issues, in addition to a broken LCD screen.
|
||||
* The repair of the LCD screen took almost a month, and concluded
|
||||
with me receiving a worse quality screen than I originally had.
|
||||
* The system replacement that followed the botched LCD repair took
|
||||
over a month to go through.
|
||||
* The replaced system was made partially of used parts, which
|
||||
DELL refused to admit.
|
||||
* The microphone on the replacement system was broken.
|
||||
|
||||
### Closing Thoughts
|
||||
I will not be sending my system in again. It doesn't make sense to do so -
|
||||
after mailing my system in for repairs three times, I've measured empirically that
|
||||
the chance of failure is 100%. Every service request is a lottery, dutifully
|
||||
giving out a random prize of another broken part. I no longer wish to play;
|
||||
as any person who gambles should, I will quit while I'm ahead, and cut my losses.
|
||||
However, I hope for this story, which may be unusual in its level of detail,
|
||||
but not its content, to be seen by seen by someone. I hope to prevent
|
||||
someone out there from feeling the frustration, and anger, and peculiar amusement
|
||||
that I felt during this process. I hope for someone else to purchase a computer
|
||||
with money, and not with their sanity. A guy can hope.
|
||||
|
||||
If you're reading this, please take this as a warning. __DELL is a horrible
|
||||
company. They have the lowest standards of customer support of any
|
||||
U.S. company that I've encountered. Their technicians are largely incompetent.
|
||||
Their quality assurance is non-existent. Stay away from them.__
|
||||
BIN
content/blog/dell_is_horrible/reviews_1.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
content/blog/dell_is_horrible/reviews_2.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
@@ -12,7 +12,7 @@ __py-starbound__, nicely enough, actually has a file named `FORMATS.md`. This fi
|
||||
> This section will contain information on how to retrieve a value from a BTreeDB5 database.
|
||||
|
||||
Not very helpful. Before I go into what I managed to determine from the code, we may first take a look at one thing that we already know about the world format - it is a [B-Tree](https://en.wikipedia.org/wiki/B-tree).
|
||||
## Binary Search Trees
|
||||
### Binary Search Trees
|
||||
The B-Tree is a generalization of a Binary Search Tree, or BST for short. Binary Search trees (and B-Trees in general) operate on data that can be ordered consistently, the simplest example being numbers. For instance, as an example, I'll be using a BST that holds integers. A BST is made up of nodes, objects that actually hold the pieces of data that the tree itself organizes.
|
||||
|
||||
In a BST, the nodes are organized in a simple way. Each node can have up to two _children_ (sub-nodes), and each of those can have up to two children, etc. The children are generally classified as _right_ and _left_. Conventionally, left children always have a value that is below (or comes before) the value of the node whose child they are (their _parent_), and right children have a bigger value.
|
||||
@@ -45,7 +45,7 @@ __Although the average efficiency of a Binary Search Tree is \\(O(\log n)\\), me
|
||||
|
||||
This isn't good enough, and many clever algorithms have been invented to speed up the lookup of the tree by making sure that it remains _balanced_ - that is, it _isn't_ arranged like a simple list. Some of these algorithms include [Red-Black Trees](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree), [AVL Trees](https://en.wikipedia.org/wiki/AVL_tree), and, of course, B-Trees.
|
||||
|
||||
## B-Trees
|
||||
### B-Trees
|
||||
B-Trees are a generalization of Binary Search Trees. That means that every Binary Search Tree is a B-Tree, but not all B-Trees are BSTs. The key difference lies in the fact that B-Trees' nodes aren't limited to having only two child nodes, and can also have more than one value.
|
||||
|
||||
Each B-Tree node is a sorted array of values. That is, instead of a single number like the BST that we've looked at, it has multiple, and these numbers _must_ be sorted. Below are some examples of B-Tree nodes:
|
||||
@@ -64,7 +64,7 @@ This is solved using another property of B-Trees - the number of children of a n
|
||||
|
||||
If we were looking for the number 15, we'd look between the 10 and the 20, examining the 2nd node, and if we were looking for 45 we'd look past the 30, at the 4th node.
|
||||
|
||||
## Starbound B-Trees and BTreeDB5
|
||||
### Starbound B-Trees and BTreeDB5
|
||||
The BTreeDB5 data structure uses something other than integers for its keys - it uses sequences of bytes. These bytes are compared in a very similar fashion to integers. The game first looks at the first number in the sequence of bytes (like the largest digit in an integer), and if that's the same, moves on to the next one. Also, Starbound B-Trees not only have the values, or _keys_, that they use to find data, but the data itself.
|
||||
|
||||
The "nodes" in the BTreeDB are called "blocks" and are one of three types - "index", "leaf", and "free" nodes. "Index" nodes are like the `(10, 20, 30)` node in the above example - they point to other nodes, but actually store no data themselves. The "leaf" nodes actually contain the data, and, if that data is longer than the maximum block size, "leaf" nodes contain the index of the next leaf node where the user might continue to read the data. The "free" nodes are simply free data, empty and ready for Starbound to fill them with something useful.
|
||||
|
||||
BIN
static/Resume-Danila-Fedorin.pdf
Normal file
@@ -2,20 +2,21 @@
|
||||
@import "mixins.scss";
|
||||
|
||||
$margin-width: 30rem;
|
||||
$margin-offset: 1.5rem;
|
||||
$margin-inner-offset: 0.5rem;
|
||||
$margin-outer-offset: 1rem;
|
||||
|
||||
@mixin below-two-margins {
|
||||
@media screen and
|
||||
(max-width: $container-width +
|
||||
2 * ($margin-width + 2 * $margin-offset)) {
|
||||
(max-width: $container-width-threshold +
|
||||
2 * ($margin-width + $margin-inner-offset + $margin-outer-offset)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin below-one-margin {
|
||||
@media screen and
|
||||
(max-width: $container-width +
|
||||
($margin-width + 3 * $margin-offset)) {
|
||||
(max-width: $container-width-threshold +
|
||||
($margin-width + $margin-inner-offset + $margin-outer-offset)) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@@ -29,10 +30,18 @@ $margin-offset: 1.5rem;
|
||||
|
||||
@mixin margin-content-left {
|
||||
left: 0;
|
||||
margin-left: -($margin-width + $margin-offset);
|
||||
margin-left: -($margin-width + $container-min-padding + $margin-inner-offset);
|
||||
|
||||
@include below-two-margins {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin margin-content-right {
|
||||
right: 0;
|
||||
margin-right: -($margin-width + $margin-offset);
|
||||
margin-right: -($margin-width + $container-min-padding + $margin-inner-offset);
|
||||
|
||||
@include below-one-margin {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
@mixin below-container-width {
|
||||
@media screen and (max-width: $container-width){
|
||||
@media screen and (max-width: $container-width-threshold){
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
@import "mixins.scss";
|
||||
@import "margin.scss";
|
||||
|
||||
$sidenote-width: 30rem;
|
||||
$sidenote-offset: 1.5rem;
|
||||
$sidenote-padding: 1rem;
|
||||
$sidenote-highlight-border-width: .2rem;
|
||||
|
||||
@@ -56,7 +54,6 @@ $sidenote-highlight-border-width: .2rem;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
width: 100%;
|
||||
display: none;
|
||||
|
||||
.sidenote-checkbox:checked ~ & {
|
||||
display: block;
|
||||
@@ -71,10 +68,6 @@ $sidenote-highlight-border-width: .2rem;
|
||||
}
|
||||
|
||||
@include below-one-margin {
|
||||
.post-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.sidenote-content.sidenote-right {
|
||||
@include hidden-sidenote;
|
||||
margin-right: 0rem;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@import "variables.scss";
|
||||
@import "mixins.scss";
|
||||
@import "margin.scss";
|
||||
@import "toc.scss";
|
||||
|
||||
body {
|
||||
font-family: $font-body;
|
||||
@@ -39,13 +40,22 @@ pre code {
|
||||
display: block;
|
||||
padding: 0.5rem;
|
||||
overflow-x: auto;
|
||||
background-color: $code-color;
|
||||
border: $code-border;
|
||||
}
|
||||
|
||||
div.highlight table pre {
|
||||
div.highlight table {
|
||||
border: $code-border !important;
|
||||
border-radius: 0px;
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
margin: auto;
|
||||
@@ -54,15 +64,17 @@ div.highlight table pre {
|
||||
box-sizing: border-box;
|
||||
|
||||
@include below-container-width {
|
||||
padding: 0rem 1rem 0rem 1rem;
|
||||
padding: 0 $container-min-padding 0 $container-min-padding;
|
||||
margin: 0;
|
||||
max-width: $container-width + 2 * $container-min-padding;
|
||||
}
|
||||
|
||||
@include below-two-margins {
|
||||
left: -($margin-width + $margin-offset)/2;
|
||||
left: -($margin-width + $margin-inner-offset + $margin-outer-offset)/2;
|
||||
}
|
||||
|
||||
@include below-one-margin {
|
||||
position: initial;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +83,7 @@ div.highlight table pre {
|
||||
background-color: $primary-color;
|
||||
border: none;
|
||||
color: white;
|
||||
transition: color 0.25s;
|
||||
transition: background-color 0.25s;
|
||||
transition: color 0.25s, background-color 0.25s;
|
||||
text-align: left;
|
||||
|
||||
&:focus {
|
||||
@@ -231,3 +242,7 @@ figure {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.twitter-tweet {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
49
themes/vanilla/assets/scss/toc.scss
Normal file
@@ -0,0 +1,49 @@
|
||||
@import "variables.scss";
|
||||
@import "mixins.scss";
|
||||
|
||||
$toc-color: $code-color;
|
||||
$toc-border-color: $code-border-color;
|
||||
|
||||
.table-of-contents {
|
||||
@include margin-content;
|
||||
@include margin-content-left;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: end;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
#TableOfContents > ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
nav {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 2rem;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
a {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.wrapper {
|
||||
@include bordered-block;
|
||||
padding: 1rem;
|
||||
background-color: $toc-color;
|
||||
border-color: $toc-border-color;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
$container-width: 45rem;
|
||||
$container-min-padding: 1rem;
|
||||
$container-width-threshold: $container-width + 2 * $container-min-padding;
|
||||
$standard-border-width: .075rem;
|
||||
|
||||
$primary-color: #36e281;
|
||||
$primary-color-dark: darken($primary-color, 10%);
|
||||
$code-color: #f0f0f0;
|
||||
$code-color-dark: darken($code-color, 10%);
|
||||
$border-color: #bfbfbf;
|
||||
$code-color: #f0f0f0;
|
||||
$code-border-color: darken($code-color, 10%);
|
||||
|
||||
$font-heading: "Lora", serif;
|
||||
$font-body: "Raleway", serif;
|
||||
$font-code: "Inconsolata", monospace;
|
||||
|
||||
$standard-border: $standard-border-width solid $border-color;
|
||||
$code-border: $standard-border-width solid $code-border-color;
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
</div>
|
||||
|
||||
<div class="post-content">
|
||||
{{ if not (eq .TableOfContents "<nav id=\"TableOfContents\"></nav>") }}
|
||||
<div class="table-of-contents">
|
||||
<div class="wrapper">
|
||||
<em>Table of Contents</em>
|
||||
{{ .TableOfContents }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ .Content }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
<nav>
|
||||
<div class="container">
|
||||
<a href="/">Home</a>
|
||||
<a href="https://github.com/DanilaFe">GitHub</a>
|
||||
<a href="/about">About</a>
|
||||
<a href="https://github.com/DanilaFe">GitHub</a>
|
||||
<a href="/Resume-Danila-Fedorin.pdf">Resume</a>
|
||||
<a href="/tags">Tags</a>
|
||||
<a href="/blog">All Posts</a>
|
||||
</div>
|
||||
|
||||