Thursday, January 7, 2016

Breaking URLs anywhere in (Lua)LaTeX (even in itemize, enumerate, adjustwidth, etc. environments)

\( \LaTeX \) is fantastic, but sometimes it does strange things, like breaking \urls only at certain points. Using tricks like this glorious \UrlBreaks hack, one can force URLs to break at any point, but for some reason, this does not work in environments like itemize, enumerate and adjustwidth, so doesn't work in BibLaTeX bibliographies.

To overcome this problem, one can manually insert \allowbreaks, but that seems a little s\allowbreaki\allowbreakl\allowbreakl\allowbreaky.

The solution: use Lua to do the hard work.

betterurl.lua
function betterurl(text)
    label = text:gsub(".", "%1\\allowbreak{}")
    
    label = label:gsub("~", "\\textasciitilde")
    label = label:gsub("&", "\\&") 
    
    -- insert other URL symbols here
    
    url = text
    
    tex.print("\\href{" .. url .. "}{\\texttt{" .. label .. "}}")
end


LaTeX preamble
\usepackage{luacode}

\luaexec{require("betterurl")}
\renewcommand{\url}[1]{\luadirect{
    betterurl(\luastringN{#1})
}}

Labels: , , , , ,

Saturday, March 14, 2015

Random Question Generator on Anki using JavaScript

Introduction

Anki is brilliant. It has really lived up to its motto ‘Remember Anything, Remember Anywhere, Remember Efficiently’ for being my go-to way to remember notes and other information. This is made all the more powerful through its HTML-based card system, which includes support for complex behaviour via JavaScript. Unfortunately, utilising JavaScript to perform such behaviour is less than straightforward.

Fortunately, I've done all the hard work for you, so here's a guide on using JavaScript in Anki. I used it to generate physics questions and associated solutions, but the general idea should be applicable to any use case.

Getting JavaScript into Anki

Although the ‘Add Note’ screen in Anki allows HTML and JavaScript input, any JavaScript input here is automatically executed during the editing stage, which is not exactly helpful for creating dynamic content.
Instead, JavaScript needs to be set up from within the card template. To do this, create a new note type by accessing the Add Note screen, then clicking the note type (Basic, in the images above), Manage, Add, Add: Basic, OK.
Give it a name like ‘Script’, then go back to the Choose Note Type window and choose the new note type.
Click the Cards… button, and at the beginning of the Front Template, add some JavaScript. If all goes well, the Front Preview should show the results of the JavaScript code.

Custom Per-Card JavaScript

Now creating a new note type for every single piece of JavaScript you want to add is impractical, so let's find a way to make the note type execute code based on a per-card field. At the beginning of the Front Template, replace the previous JavaScript code with:
var code = (function () {/* {{Script}} */}).toString();
code = code.replace(/^[^\/]+\/\*!?/, "").replace(/\*\/[^\/]+$/, ""); //Strip beginning/ending comments.
code = code.replace(/<div>/g, "\n").replace(/<\/div>/g, "\n").replace(/<br \/>/g, "\n"); //Strip HTML.
code = code.replace(/&nbsp;/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&"); //Replace special symbols.
eval(code);
The first two lines take the HTML code of a per-card Script field and store it in a JavaScript variable. The third and fourth lines strip extraneous HTML code from the variable, hopefully turning it into executable JavaScript code. Depending on which symbols you use, you may need to add more replacements to the fourth line. The final line executes the JavaScript code.

Right now, the code won't work, because the Script field has not been declared. Close the Card Types for Script window, click the Fields… button, and add a new Script field.
Now, any code in the Script field will be executed each time the card is shown, once for the front, then again later for the back.
In order to access the contents of the card more easily from within JavaScript, some changes can be made to the Front Template and Back Template, giving each side an id attribute:
Note that if you want to access these, you will need to delay the call until after the DOM has finished loading, by wrapping your JavaScript in window.setTimeout(function(){}, 0); or something similar.

Data Persistence

Depending on what you want to do, the above technique will work perfectly. More likely, however, is that the fact the JavaScript is executed twice will cause problems for you. The images below show a common scenario, wherein the generated question changes when flipping sides of the card. Not useful for checking your answer!
Thus, we need a way of storing data within the JavaScript code across executions of the same card. Unfortunately, typical ways of doing this, localStorage and document.cookie are disabled. From a ‘normal’ JavaScript point of view, each execution is entirely separate from the other.

Thankfully, Anki exposes a behind-the-scenes window.py object. The internal functions exposed by the object are pretty useless, but the instance of the object is shared between executions of the same card (and reset if the card is shown again later), meaning that it can be used to store data between executions.

Using the below code to store randomly generated data between executions allows us to overcome this restriction.
window.setTimeout(function() {
var o = (typeof py === "undefined") ? {} : py; //Attempt to use Anki's Bridge object to store data across sides.
o.data = o.data || {};

o.data.num = o.data.num || Math.random();
if (document.getElementById("front")) document.getElementById("front").innerHTML = "The number on the front is " + o.data.num;
if (document.getElementById("back")) document.getElementById("back").innerHTML = "The number on the back is " + o.data.num;
}, 0); //Execute after Anki has loaded its Bridge object.


Anki+JavaScript in Action


Tuesday, January 20, 2015

Optimisation of a composite function involving a differentiable monotonic component

While doing optimisation problems with calculus I often find myself needing to optimise expressions such as \( \sqrt{\sin x} \), though often more complicated. Using the chain rule on the square root is time-consuming, and it seems logical that as a monotonically increasing function, the square root shouldn't affect the x-coordinate of the local minima and maxima. Thus, I give you…

Theorem

If \( g(f(x)) \) is a composite function, and \( g \) is a monotonic function, and is differentiable \( g \) in some domain;
Then the x-coordinates of the local minima and maxima of \( g(f(x)) \) in that domain are the same as the those of \( f(x) \).

Proof

Using the chain rule to find the derivative of \( g(f(x)) \) with respect to \( x \):
\[ \begin{aligned}
\frac{\mathrm{d}g}{\mathrm{d}x} &= \frac{\mathrm{d}g}{\mathrm{d}f} \cdot \frac{\mathrm{d}f}{\mathrm{d}x}
\end{aligned} \]
By Fermat's theorem, each local minimum and maximum of \( g(f(x)) \) must be at a critical point \( x_{\text{critical}} \); where \( \frac{\mathrm{d}g}{\mathrm{d}x} \) is equal to 0 or undefined:
\[ \begin{aligned}
\left(\frac{\mathrm{d}g}{\mathrm{d}x}\right)_{x = x_{\text{critical}}} &= 0\text{ or undefined} \\
\left(\frac{\mathrm{d}g}{\mathrm{d}f}\right)_{x = x_{\text{critical}}} \cdot \left(\frac{\mathrm{d}f}{\mathrm{d}x}\right)_{x = x_{\text{critical}}} &= 0\text{ or undefined}
\end{aligned} \]
By the zero-product property (null factor law),
\[ \begin{aligned}
\left(\frac{\mathrm{d}g}{\mathrm{d}f}\right)_{x = x_{\text{critical}}} &= 0\text{ or undefined} \\
&\text{and/or} \\ \left(\frac{\mathrm{d}f}{\mathrm{d}x}\right)_{x = x_{\text{critical}}} &= 0\text{ or undefined}
\end{aligned} \]
Since \( g \) is a monotonic function, \( \frac{\mathrm{d}g}{\mathrm{d}f} \) is never equal to 0. Additionally, since the derivative of \( g \) is always defined in the relevant domain, \( \frac{\mathrm{d}g}{\mathrm{d}f} \) is never undefined.
Therefore,
\[ \begin{aligned}
\left(\frac{\mathrm{d}f}{\mathrm{d}x}\right)_{x = x_{\text{critical}}} &= 0\text{ or undefined}
\end{aligned} \]
Therefore, each critical point on \( g(f(x)) \) is at the same x-coordinate as that on \( f(x) \), and by extension, each local minimum and maximum of \( g(f(x)) \) is at the same x-coordinate as that of \( f(x) \).

Q.E.D.

Disclaimer

I am not a mathematician. As far as I can tell, the above is not any ‘official’ theorem. There are probably some small errors in terminology and corner cases that I forgot to account for. Exercise common sense when applying the above.

Labels: , , , ,

Monday, August 18, 2014

GUIDE: Automatically resize phpBB avatars in post displays

  1. Open the includes/functions_display.php file in a text editor.
  2. Above the return '<img src="' . (str_replace( … line, insert the code:
    $inputwidth = 100;
    $inputheight = 100;
    
    // So then if the image is wider rather than taller, set the width and figure out the height
    if (($avatar_width/$avatar_height) > ($inputwidth/$inputheight)) {
     $outputwidth = $inputwidth;
     $outputheight = ($inputwidth * $avatar_height)/ $avatar_width;
    }
    // And if the image is taller rather than wider, then set the height and figure out the width
    elseif (($avatar_width/$avatar_height) < ($inputwidth/$inputheight)) {
     $outputwidth = ($inputheight * $avatar_width)/ $avatar_height;
     $outputheight = $inputheight;
    }
    // And because it is entirely possible that the image could be the exact same size/aspect ratio of the desired area, so we have that covered as well
    elseif (($avatar_width/$avatar_height) == ($inputwidth/$inputheight)) {
     $outputwidth = $inputwidth;
     $outputheight = $inputheight;
    }
  3. Change the $inputwidth and $inputheight variables to suit your needs.
  4. Replace the return '<img src="' . (str_replace( … line with:
    return '<img src="' . (str_replace(' ', '%20', $avatar_img)) . '" width="' . $outputwidth . '" height="' . $outputheight . '" alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';

Wednesday, June 11, 2014

FIX: Steam crashes when using radeon driver

Symptoms

Steam crashes upon opening, after verifying the installation and before opening the main interface, with something about the OpenGL context not supporting direct rendering. Soon afterwards, the X server crashes. (I'm not crashing my computer again just to find the exact error message, thank you very much!)

Problem

The problem here is (at least on my computer) that Steam ships a copy of libstcd++ (amongst other things) that is incompatible with the radeon drivers.

Solution 1: The Easy Way

The easiest solution to this problem is to replace the offending library with the one from your system. Run Steam again, logging the output to a file:
steam 2&>1 | tee steam.log
When Steam inevitably crashes again, open the log file and find the line complaining about ‘libgcc_s.so.1’ or ‘libstcd++.so.9001.42π’ or something. Navigate to the directory containing the offending file. On my system, this was:
cd /home/runassudo/.local/share/Steam/ubuntu12_32/steam-runtime/i386/usr/lib/i386-linux-gnu
Move the offending library somewhere safe:
mv libgcc_s.so.1 libgcc_s.so.1.bak
Now create a symlink to your system's copy of the library. On my system, this was:
ln -s /usr/lib32/libgcc_s.so.1
Remember to link to the 32-bit version of the library! If unsure, check with file:
file /usr/lib/libgcc_s.so.1
Look for a line saying ‘32-bit’ or ‘64-bit’.

Solution 2: The Proper Way

The above solution should work, but it seems a little hacky. The proper method is to disable the steam runtime entirely. Make sure you've got all the required libraries on your system!

Labels: , , , , , , , , ,

Thursday, May 1, 2014

Evil Bash Scripts: Sudo Impersonator

[runassudo@NEXUS tmp]$ cat awesomeprogram
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root"
else
   echo "Sorry, try again."
   echo -n "[sudo] password for $SUDO_USER: "
   read -s tmp
   echo ""
   echo "PASSWORD IS $tmp"
   # Do evil things
fi
[runassudo@NEXUS tmp]$ ./awesomeprogram
This script must be run as root
[runassudo@NEXUS tmp]$ sudo ./awesomeprogram
[sudo] password for runassudo: 
Sorry, try again.
[sudo] password for runassudo: 
PASSWORD IS password

Labels: ,

Monday, March 31, 2014

FIX: LoL errors on (PlayOn) Linux

Problem

‘The game has crashed. Please try to reconnect.’ immediately after champion select.

Solution

Open /etc/hosts on the host computer in the text editor of your choice.
On the line that resembles:
127.0.0.1   localhost.localdomain   localhost
add the name of your computer (found in /etc/hostname). For example:
127.0.0.1   localhost.localdomain   localhost   NEXUS

Problem

‘Unable to connect to server. If you have a firewall, it may be blocking the connection. Please refer to your firewall's documentation. Would you like to retry the connection? [Retry] [Cancel]’ after champion select.

Solution

Open winecfg (if on PlayOnLinux, use Configure -> Wine -> Configure Wine). Go to Libraries. Add the override dnsapi (builtin, native).

Labels: , , , , , ,