<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>hashman.ca</title><link href="https://hashman.ca/" rel="alternate"></link><link href="https://hashman.ca/feeds/all.atom.xml" rel="self"></link><id>https://hashman.ca/</id><updated>2026-01-26T21:00:00-05:00</updated><entry><title>A beginner's guide to improving your digital security</title><link href="https://hashman.ca/security-101/" rel="alternate"></link><published>2026-01-26T21:00:00-05:00</published><updated>2026-01-26T21:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2026-01-26:/security-101/</id><summary type="html">&lt;p&gt;This 8 item to-do list will help you improve your security, understand why you should do each task, the limitations of these tools, and what not to do.&lt;/p&gt;</summary><content type="html">&lt;p&gt;In 2017, I led a &lt;a href="/protect-yoself"&gt;series of workshops&lt;/a&gt; aimed at teaching
beginners a better understanding of encryption, how the internet works, and
their digital security. Nearly a decade later, there is still a great need to
share reliable resources and guides on improving these skills.&lt;/p&gt;
&lt;p&gt;I have worked professionally in computer security one way or another for well
over a decade, at &lt;a href="/about"&gt;many major technology companies and in many open source
software projects&lt;/a&gt;. There are many inaccurate and unreliable resources
out there on this subject, put together by well-meaning people without a
background in security, which can lead to sharing misinformation, exaggeration
and fearmongering.&lt;/p&gt;
&lt;p&gt;I hope that I can offer you a trusted, curated list of high impact things that
you can do right now, using whichever vetted guide you prefer. In addition, I
also include how long it should take, why you should do each task, and any
limitations.&lt;/p&gt;
&lt;p&gt;This guide is aimed at improving your personal security, and does not apply to
your work-owned devices. &lt;em&gt;Always assume your company can monitor all of your
messages and activities on work devices.&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;What can I do to improve my security right away?&lt;/h1&gt;
&lt;p&gt;I put together this list in order of effort, easiest tasks first. You should be
able to complete many of the low effort tasks in a single hour. The medium to
high effort tasks are very much worth doing, but may take you a few days or
even weeks to complete them.&lt;/p&gt;
&lt;h2&gt;Low effort (&amp;lt;15 minutes)&lt;/h2&gt;
&lt;p&gt;&lt;a name="upgrades"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Upgrade your software to the latest versions&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; I don't know anyone who hasn't complained about software updates
breaking features, introducing bugs, and causing headaches. If it ain't broke,
why upgrade, right? Well, alongside all of those annoying bugs and breaking
changes, software updates also include security fixes, which will &lt;em&gt;protect your
device from being exploited&lt;/em&gt; by bad actors. Security issues can be found in
software at any time, even software that's been available for many years and
thought to be secure. You want to install these as soon as they are available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; Turn on automatic upgrades and always keep your devices as
up-to-date as possible. If you have some software you know will not work if you
upgrade it, at least be sure to upgrade your laptop and phone operating system
(iOS, Android, Windows, etc.) and web browser (Chrome, Safari, Firefox, etc.).
Do not use devices that do not receive security support (e.g. old Android or
iPhones).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://activistchecklist.org/essentials/#updates"&gt;Activist Checklist: Install the latest software updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Consumer Reports: Update your &lt;a href="https://securityplanner.consumerreports.org/tool/update-your-mac"&gt;Mac&lt;/a&gt;, &lt;a href="https://securityplanner.consumerreports.org/tool/update-your-windows-pc/"&gt;Windows PC&lt;/a&gt;, &lt;a href="https://securityplanner.consumerreports.org/tool/update-your-chromebook"&gt;Chromebook&lt;/a&gt;, &lt;a href="https://securityplanner.consumerreports.org/tool/update-your-android-phone"&gt;Android phone&lt;/a&gt;, &lt;a href="https://securityplanner.consumerreports.org/tool/update-your-iphone-ipad-ipod-touch"&gt;iOS device&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.apple.com/en-us/102772"&gt;Apple: Obsolete products&lt;/a&gt; (obsolete
  devices do not receive security updates)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.google.com/pixelphone/answer/4457705?hl=en"&gt;Google: How long you'll get Pixel updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://security.samsungmobile.com/workScope.smsb"&gt;Samsung: Devices that receive security updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Other brands: check the manufacturer's website&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; This will prevent someone from exploiting known security
issues on your devices, but it won't help if your device was already
compromised. If this is a concern, doing a factory reset, upgrade, and turning
on automatic upgrades may help. This also won't protect against all types of
attacks, but it is a necessary foundation.&lt;/p&gt;
&lt;p&gt;&lt;a name="signal"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Use Signal&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; &lt;a href="https://signal.org/download/"&gt;Signal&lt;/a&gt; is a trusted, vetted, secure
messaging application that allows you to send end-to-end encrypted messages and
make video/phone calls. This means that only you and your intended recipient
can decrypt the messages and someone cannot intercept and read your messages,
in contrast to texting (SMS) and other insecure forms of messaging. Other
applications advertise themselves as end-to-end encrypted, but &lt;a href="https://www.tomsguide.com/news/signal-vs-telegram"&gt;Signal provides
the strongest protections&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; I recommend installing the Signal app and using it! My mom
loves that she can video call me on Wi-Fi on my Android phone. It also supports
group chats. I use it as a secure alternative to texting (SMS) and other chat
platforms. I also like Signal's "disappearing messages" feature which I enable
by default because it automatically deletes messages after a certain period of
time. This avoids your messages taking up too much storage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://activistchecklist.org/essentials/#signal"&gt;Activist Checklist: Use Signal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://activistchecklist.org/essentials/#signal-disappearing"&gt;Activist Checklist: Turn on disappearing messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ssd.eff.org/module/how-to-use-signal"&gt;Electronic Frontier Foundation: How to use Signal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://securityplanner.consumerreports.org/tool/text-call-privately-with-signal/"&gt;Consumer Reports: Communicate privately with Signal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.signal.org/hc/en-us/articles/360055276112-Incognito-Keyboard"&gt;Signal: Enabling Incognito Keyboard (Android)&lt;/a&gt; to provide slightly more privacy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; Signal is only able to protect your messages in transit. If
someone has access to your phone or the phone of the person you sent messages
to, they will still be able to read them. As a rule of thumb, if you don't want
someone to read something, &lt;em&gt;don't write it down!&lt;/em&gt; Meet in person or make an
encrypted phone call where you will not be overheard. If you are talking to
someone you don't know, assume your messages are as public as posting on social
media.&lt;/p&gt;
&lt;p&gt;&lt;a name="passwords-and-encryption"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Set passwords and turn on device encryption&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; Passwords ensure that someone else can't unlock your device without
your consent or knowledge. They also are required to turn on device encryption,
which protects your information on your device from being accessed when it is
locked. Biometric (fingerprint or face ID) locking provides some privacy, but
your fingerprint or face ID can be used against your wishes, whereas if you are
the only person who knows your password, only you can use it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; Always set passwords and have device encryption enabled in
order to protect your personal privacy. It may be convenient to allow kids or
family members access to an unlocked device, but anyone else can access it,
too! Use strong passwords that cannot be guessed&amp;mdash;avoid using names,
birthdays, phone numbers, addresses, or other public information. Using a
&lt;a href="#password-manager"&gt;password manager&lt;/a&gt; will make creating and managing passwords
even easier. Disable biometric unlock, or at least know how to disable it. Most
devices will enable disk encryption by default, but you should double-check.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ssd.eff.org/module/creating-strong-passwords"&gt;Electronic Frontier Foundation: Creating strong passwords&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ssd.eff.org/module/attending-protest#remove-fingerprint-or-face-unlock"&gt;Electronic Frontier Foundation: Remove fingerprint or face unlock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.howtogeek.com/814149/your-phone-has-a-biometric-kill-switch-heres-why-you-should-use-it/"&gt;How-To Geek: Temporarily disable biometric unlock on Android and iOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Electronic Frontier Foundation: &lt;a href="https://ssd.eff.org/module/how-encrypt-your-windows-device"&gt;How to encrypt your Windows, Mac, or Linux computer&lt;/a&gt;, &lt;a href="https://ssd.eff.org/module/how-encrypt-your-iphone"&gt;your iPhone&lt;/a&gt;, &lt;a href="https://ssd.eff.org/module/how-to-get-to-know-android-privacy-and-security-settings"&gt;Android Privacy and Security settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Consumer Reports: Protect your &lt;a href="https://securityplanner.consumerreports.org/tool/encrypt-your-mac"&gt;Mac&lt;/a&gt;, &lt;a href="https://securityplanner.consumerreports.org/tool/encrypt-your-windows-pc"&gt;Windows PC&lt;/a&gt;, &lt;a href="https://securityplanner.consumerreports.org/tool/encrypt-your-android-phone"&gt;Android phone&lt;/a&gt;, &lt;a href="https://securityplanner.consumerreports.org/tool/encrypt-your-iphone"&gt;iPhone&lt;/a&gt; devices with encryption&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a name="forensics"&gt;&lt;/a&gt;
&lt;strong&gt;Limitations:&lt;/strong&gt; If your device is unlocked, the password and encryption will
provide no protections; the device must be locked for this to protect your
privacy. It is possible, though unlikely, for someone to gain remote access to
your device (for example through malware or
&lt;a href="https://www.malwarebytes.com/stalkerware"&gt;stalkerware&lt;/a&gt;), which would bypass
these protections. Some &lt;a href="https://sls.eff.org/technologies/forensic-extraction-tools"&gt;forensic
tools&lt;/a&gt; are also
sophisticated enough to work with physical access to a device that is turned on
and locked, but not a device that is turned off/freshly powered on and
encrypted. If you lose your password or disk encryption key, you may lose
access to your device. For this reason, Windows and Apple laptops can make a
cloud backup of your disk encryption key. However, a cloud backup can
potentially be &lt;a href="https://www.zdnet.com/article/windows-pc-bitlocker-encryption-may-be-shared-with-law-enforcement-how-to-protect-privacy/"&gt;disclosed to law
enforcement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a name="ad-blockers"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Install an ad blocker&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; Online ad networks are often &lt;a href="https://www.malwarebytes.com/malvertising"&gt;exploited to spread 
malware&lt;/a&gt; to unsuspecting visitors.
If you've ever visited a regular website and suddenly seen an urgent, flashing
pop-up claiming your device was hacked, it is often due to a bad ad. Blocking
ads provides an additional layer of protection against these kinds of attacks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; I recommend everyone uses an ad blocker at all times. Not
only are ads annoying and disruptive, but they can even result in your devices
being compromised!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://securityplanner.consumerreports.org/tool/reduce-online-tracking/#3-add-an-ad-blocker"&gt;Consumer Reports: Add an ad blocker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ublockorigin.com/"&gt;uBlock Origin&lt;/a&gt;, a highly recommended browser-based ad blocker (Firefox, Chrome)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://adguard.com/en/welcome.html"&gt;AdGuard Ad Blocker&lt;/a&gt; is multi-platform and also supports Mac/iOS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; Sometimes the use of ad blockers can break functionality on
websites, which can be annoying, but you can temporarily disable them to fix
the problem. These may not be able to block all ads or all tracking, but they
make browsing the web much more pleasant and lower risk! Some people might also
be concerned that blocking ads might impact the revenue of their favourite
websites or creators. In this case, I recommend either donating directly or
sharing the site with a wider audience, but keep using the ad blocker for your
safety.&lt;/p&gt;
&lt;p&gt;&lt;a name="https"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Enable HTTPS-Only Mode&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; The "S" in "HTTPS" stands for "secure". This feature, which can be
enabled on your web browser, ensures that every time you visit a website, your
connection is always end-to-end encrypted (just like when you use Signal!) This
ensures that someone can't intercept what you search for, what pages on
websites you visit, and any information you or the website share such as your
banking details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; I recommend enabling this for everyone, though with
improvements in web browser security and adoption of HTTPS over the years, your
devices will often do this by default!  There is a small risk you will
encounter some websites that do not support HTTPS, usually older sites. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://securityplanner.consumerreports.org/tool/install-https-everywhere"&gt;Consumer Reports: Set Up HTTPS-Only Mode on your browser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; HTTPS protects the information on your connection to a
website. It does not hide or protect the fact that you visited that website,
only the information you accessed. If the website is malicious, HTTPS does not
provide any protection. In certain settings, like when you use a work-managed
computer that was set up for you, it can still be possible for your IT
Department to see what you are browsing, even over an HTTPS connection, because
they have administrator access to your computer and the network.&lt;/p&gt;
&lt;h2&gt;Medium to high effort (1+ hours)&lt;/h2&gt;
&lt;p&gt;These tasks require more effort but are worth the investment.&lt;/p&gt;
&lt;p&gt;&lt;a name="password-manager"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Set up a password manager&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; It is not possible for a person to remember a unique password for
every single website and app that they use. I have, as of writing, 556
passwords stored in my password manager. Password managers do three important
things very well:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;They &lt;em&gt;generate secure passwords&lt;/em&gt; with ease. You don't need to worry about
   getting your digits and special characters just right; the app will do it
   for you, and generate long, secure passwords.&lt;/li&gt;
&lt;li&gt;They &lt;em&gt;remember all your passwords&lt;/em&gt; for you, and you just need to remember one
   password to access all of them. The most common reason people's accounts get
   hacked online is because they used the same password across multiple
   websites, and one of the websites had all their passwords leaked. When you
   use a unique password on every website, it doesn't matter if your password
   gets leaked!&lt;/li&gt;
&lt;li&gt;They autofill passwords based on the website you're visiting. This is
   important because it helps &lt;em&gt;prevent you from getting
   &lt;a href="https://ssd.eff.org/module/how-avoid-phishing-attacks"&gt;phished&lt;/a&gt;&lt;/em&gt;. If you're
   tricked into visiting an evil lookalike site, your password manager will
   refuse to fill the password.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; These benefits are extremely important, and setting up a
password manager is often one of the &lt;em&gt;most impactful&lt;/em&gt; things you can do for your
digital security. However, they take time to get used to, and migrating all of
your passwords into the app (and immediately changing them!) can take a few
minutes at a time... over weeks. I recommend you &lt;em&gt;prioritize the most important
sites,&lt;/em&gt; such as your email accounts, banking/financial sites, and cellphone
provider. This process will feel like a lot of work, but you will get to enjoy
the benefits of never having to remember new passwords and the autofill
functionality for websites. My recommended password manager is
&lt;a href="https://1password.com/"&gt;1Password&lt;/a&gt;, but it stores passwords in the cloud and
costs money. There are some good free options as well if cost is a concern.
You can also use web browser- or OS-based password managers, but I do not
prefer these.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://activistchecklist.org/essentials/#password-manager"&gt;Activist Checklist: Use a password manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ssd.eff.org/module/animated-overview-using-password-managers-stay-safe-online"&gt;Electronic Frontier Foundation: An animated overview of password managers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ssd.eff.org/module/choosing-the-password-manager-that-s-right-for-you"&gt;Electronic Frontier Foundation: Choosing a password manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://securityplanner.consumerreports.org/tool/get-a-password-manager/"&gt;Consumer Reports: Get a password manager&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; Many people are concerned about the risk of using a password
manager causing all of their passwords to be compromised. For this reason, it's
very important to use a vetted, reputable password manager that has passed
audits, such as 1Password or &lt;a href="https://bitwarden.com/"&gt;Bitwarden&lt;/a&gt;. It is also
extremely important to choose a strong password to unlock your password
manager. 1Password makes this easier by generating a secret to strengthen your
unlock password, but I recommend using a &lt;a href="https://xkcd.com/936/"&gt;long, memorable
password&lt;/a&gt; in any case. Another risk is that if you
forget your password manager's password, you will lose access to all your
passwords. This is why I recommend 1Password, which has you set up an
&lt;a href="https://support.1password.com/emergency-kit/"&gt;Emergency Kit&lt;/a&gt; to recover access
to your account.&lt;/p&gt;
&lt;p&gt;&lt;a name="2fa"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Set up two-factor authentication (2FA) for your accounts&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; If your password is compromised in a website leak or due to a phishing
attack, two-factor authentication will require a second piece of information to
log in and potentially thwart the intruder. This provides you with an extra
layer of security on your accounts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; You don't necessarily need to enable 2FA on every account,
but prioritize enabling it on your most important accounts (email, banking,
cellphone, etc.) There are typically a few different kinds: email-based (which
is why your email account's security is so important), text message or
SMS-based (which is why your cell phone account's security is so important),
app-based, and hardware token-based. Email and text message 2FA are fine for
most accounts. You may want to enable app- or hardware token-based 2FA for your
most sensitive accounts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://activistchecklist.org/essentials/#mfa"&gt;Activist Checklist: Enable two-factor authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ssd.eff.org/module/how-enable-two-factor-authentication"&gt;Electronic Frontier Foundation: How to enable two-factor authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://securityplanner.consumerreports.org/tool/set-up-multifactor-authentication-mfa/"&gt;Consumer Reports: Set up multifactor authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Apps: There are many different choices available. The linked guides recommend the open source app &lt;a href="https://ente.io/auth/"&gt;Ente&lt;/a&gt;. Other options include &lt;a href="https://support.google.com/accounts/answer/1066447?hl=en"&gt;Google&lt;/a&gt; and &lt;a href="https://support.microsoft.com/en-us/account-billing/download-microsoft-authenticator-351498fc-850a-45da-b7b6-27e523b8702a"&gt;Microsoft Authenticator&lt;/a&gt;, &lt;a href="https://duo.com/product/multi-factor-authentication-mfa/duo-mobile-app"&gt;Duo&lt;/a&gt;, etc.&lt;/li&gt;
&lt;li&gt;Hardware tokens: Common choices include &lt;a href="https://www.yubico.com/products/"&gt;Yubikey&lt;/a&gt; and Google's &lt;a href="https://cloud.google.com/security/products/titan-security-key"&gt;Titan Security Key&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; The major limitation is that if you lose access to 2FA, you
can be locked out of an account. This can happen if you're travelling abroad
and can't access your usual cellphone number, if you break your phone and you
don't have a backup of your authenticator app, or if you lose your
hardware-based token. For this reason, many websites will provide you with
"backup tokens"&amp;mdash;you can print them out and store them in a secure location or &lt;a href="https://1password.com/blog/1password-2fa-passwords-codes-together"&gt;use your password manager&lt;/a&gt;. 
I also recommend if you use an app, you choose one that will allow you to make
secure backups, such as Ente. You are also limited by the types of 2FA a
website supports; many don't support app- or hardware token-based 2FA.&lt;/p&gt;
&lt;p&gt;&lt;a name="data-brokers"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Remove your information from data brokers&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; This is a problem that mostly affects people in the US. It surprises
many people that information from their credit reports and other public records
is scraped and available (for free or at a low cost) online through "data
broker" websites. I have shocked friends who didn't believe this was an issue
by searching for their full names and within 5 minutes being able to show them
their birthday, home address, and phone number. This is a serious privacy
problem!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; Opt out of any and all data broker websites to remove this
information from the internet. This is especially important if you are at risk
of being stalked or harassed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guides:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://securityplanner.consumerreports.org/tool/people-search-sites"&gt;Consumer Reports: Remove your contact information from people-search sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ssd.eff.org/module/how-to-manage-your-digital-footprint"&gt;Electronic Frontier Foundation: Manage your digital footprint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yaelwrites/Big-Ass-Data-Broker-Opt-Out-List"&gt;Big Ass Data Broker Opt Out List (BADBOOL)&lt;/a&gt;, maintained by &lt;a href="https://yaelwrites.com/contact/"&gt;Yael Grauer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;State-specific tools for residents of: &lt;a href="https://privacy.ca.gov/drop/"&gt;California&lt;/a&gt;, &lt;a href="https://dfr.oregon.gov/financial/protect/Pages/consumer-privacy-resources.aspx"&gt;Oregon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt; It can take time for your information to be removed once you
opt out, and unfortunately search engines may have cached your information for
a while longer. This is also not a one-and-done process. New data brokers are
constantly popping up and some may not properly honour your opt out, so you
will need to check on a regular basis (perhaps once or twice a year) to make
sure your data has been properly scrubbed. This also cannot prevent someone
from directly searching public records to find your information, but that
requires much more effort.&lt;/p&gt;
&lt;h1&gt;"Recommended security measures" I think beginners should avoid&lt;/h1&gt;
&lt;p&gt;We've covered a lot of tasks you should do, but I also think it's important to
cover what &lt;em&gt;not&lt;/em&gt; to do. I see many of these tools recommended to security
beginners, and I think that's a mistake. For each tool, I will explain my
reasoning around why I don't think you should use it, and the scenarios in
which it might make sense to use.&lt;/p&gt;
&lt;p&gt;&lt;a name="not-so-secure-email"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;"Secure email"&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt; Many email providers, such as
&lt;a href="https://proton.me/mail"&gt;Proton Mail&lt;/a&gt;, advertise themselves as providing secure
email. They are often recommended as a "more secure" alternative to typical
email providers such as GMail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's the problem?&lt;/strong&gt; Email is fundamentally insecure by design. The email
specification
(&lt;a href="https://www.rfc-editor.org/rfc/rfc3207.html#section-4"&gt;RFC-3207&lt;/a&gt;) states that
any publicly available email server MUST NOT require the use of end-to-end
encryption in transit. Email providers can of course provide additional
security by encrypting their copies of your email, and providing you access to
your email by HTTPS, but the messages themselves can always be sent without
encryption. Some platforms such as Proton Mail advertise end-to-end encrypted
emails so long as you email another Proton user. This is not truly email, but
their own internal encrypted messaging platform that follows the email format.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What should I do instead?&lt;/strong&gt; Use Signal to send encrypted messages. &lt;em&gt;NEVER&lt;/em&gt;
assume the contents of an email are secure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who should use it?&lt;/strong&gt; I don't believe there are any major advantages to using
a service such as this one. Even if you pay for a more "secure" email provider,
the &lt;a href="https://mako.cc/copyrighteous/google-has-most-of-my-email-because-it-has-all-of-yours"&gt;majority of your
emails&lt;/a&gt;
will still be delivered to people who don't. Additionally, while I don't
use or necessarily recommend their service, Google offers an &lt;a href="https://landing.google.com/intl/en_us/advancedprotection/"&gt;Advanced
Protection Program&lt;/a&gt;
for people who may be targeted by state-level actors.&lt;/p&gt;
&lt;p&gt;&lt;a name="pgp"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;PGP/GPG Encryption&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt; PGP ("Pretty Good Privacy") and GPG ("GNU Privacy Guard") are
encryption and cryptographic signing software. They are often recommended to
encrypt messages or email.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's the problem?&lt;/strong&gt; GPG is decades old and its usability has always been
terrible. It is extremely easy to accidentally send a message that you thought
was encrypted without encryption! The problems with PGP/GPG have been
&lt;a href="https://www.vice.com/en/article/pgp-gpg-efail-vulnerability/"&gt;extensively documented&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What should I do instead?&lt;/strong&gt; Use &lt;a href="#signal"&gt;Signal&lt;/a&gt; to send encrypted messages.
Again, &lt;em&gt;NEVER&lt;/em&gt; use email for sensitive information.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who should use it?&lt;/strong&gt; Software developers who contribute to projects where
there is a requirement to use GPG should continue to use it until an adequate
alternative is available. Everyone else should live their lives in PGP-free
bliss.&lt;/p&gt;
&lt;p&gt;&lt;a name="not-so-secure-phone-oses"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Installing a "secure" operating system (OS) on your phone&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt; There are a number of self-installed operating systems for
Android phones, such as &lt;a href="https://grapheneos.org/"&gt;GrapheneOS&lt;/a&gt;, that advertise
as being "more secure" than using the version of the Android operating system
provided by your phone manufacturer. They often remove core Google APIs and
services to allow you to "de-Google" your phone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's the problem?&lt;/strong&gt; These projects are relatively niche, and don't
have nearly enough resourcing to be able to respond to the high levels of
security pressure Android experiences (such as against the &lt;a href="#forensics"&gt;forensic
tools&lt;/a&gt; I mentioned earlier). You may suddenly lose security support
with no notice, as with
&lt;a href="https://calyxos.org/news/2025/08/01/a-letter-to-our-community/"&gt;CalyxOS&lt;/a&gt;.  You
need a high level of technical know-how and a lot of spare time to maintain
your device with a custom operating system, which is not a reasonable
expectation for the average person. By stripping all Google APIs such as
Google Play Services, some useful apps can no longer function. And some
law enforcement organizations have gone as far as &lt;a href="https://www.androidauthority.com/google-pixel-organized-crime-preferred-phone-3573578/"&gt;accusing people who install
GrapheneOS on Pixel phones to be
engaging in criminal activity&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What should I do instead?&lt;/strong&gt; For the best security on an Android device, use a
phone manufactured by Google or Samsung (smaller manufacturers are more
unreliable), or consider buying an iPhone. Make sure your device is receiving
security updates and up-to-date.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who should use it?&lt;/strong&gt; These projects are great for tech enthusiasts who are
interested in contributing to and developing them further. They can be used to
give new life to old phones that are not receiving security or software
updates. They are also great for people with an interest in free and open
source software and digital autonomy. But these tools are not a good choice for
a general audience, nor do they provide more practical security than using an
up-to-date Google or Samsung Android phone.&lt;/p&gt;
&lt;p&gt;&lt;a name="vpns"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Virtual Private Network (VPN) Services&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt; A virtual private network or VPN service can provide you with a
secure tunnel from your device to the location that the VPN operates. This
means that if I am using my phone in Seattle connected to a VPN in Amsterdam,
if I access a website, it appears to the website that my phone is located in
Amsterdam.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's the problem?&lt;/strong&gt; VPN services are frequently advertised as providing
security or protection from nefarious bad actors, or helping protect your
privacy. These benefits are often far overstated, and there are predatory VPN
providers that can actually be harmful. It costs money and resources to provide
a VPN, so free VPN services are especially suspect. When you use a VPN, the VPN
provider knows the websites you are visiting in order to provide you with the
service. Free VPN providers may &lt;a href="https://www.tomsguide.com/computing/vpns/60-percent-of-free-vpns-could-be-selling-your-data-by-2025"&gt;sell this
data&lt;/a&gt;
in order to cover the cost of providing the service, leaving you with less
security and privacy. The average person does not have the knowledge to be able
to determine if a VPN service is trustworthy or not. VPNs also don't provide
any additional encryption benefits if you are already using HTTPS. They may
provide a small amount of privacy benefit if you are connected to an untrusted
network with an attacker.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What should I do instead?&lt;/strong&gt; Always use HTTPS to access websites. Don't
connect to untrusted internet providers&amp;mdash;for example, use cellphone
network data instead of a sketchy Wi-Fi access point. Your local neighbourhood
coffee shop is probably fine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who should use it?&lt;/strong&gt; There are three main use cases for VPNs. The first is to
&lt;em&gt;bypass geographic restrictions&lt;/em&gt;. A VPN will cause all of your web traffic to
appear to be coming from another location. If you live in an area that has
local internet censorship policies, you can use a VPN to access the internet
from a location that lacks such policies. The second is if you know your
&lt;em&gt;internet service provider is actively hostile&lt;/em&gt; or malicious. A trusted VPN will
protect the visibility of all your traffic, including which websites you visit,
from your internet service provider, and the only thing they will be able to
see is that you are accessing a VPN. The third use case is to &lt;em&gt;access a network
that isn't connected to the public internet&lt;/em&gt;, such as a corporate intranet. I
strongly discourage the use of VPNs for "general-purpose security."&lt;/p&gt;
&lt;p&gt;&lt;a name="tor"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Tor&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt; Tor, "The Onion Router", is a free and open source software
project that provides anonymous networking. Unlike with a VPN, where the VPN
provider knows who you are and what websites you are requesting, Tor's
architecture makes it extremely difficult to determine who sent a request.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's the problem?&lt;/strong&gt; Tor is difficult to set up properly; similar to
PGP-encrypted email, it is possible to accidentally not be connected to Tor and
not know the difference. This usability has improved over the years, but Tor is
still not a good tool for beginners to use. Due to the way Tor works, it is
also extremely slow. If you have used cable or fiber internet, get ready to go
back to dialup speeds. Tor also doesn't provide perfect privacy and without a
strong understanding of its &lt;a href="https://en.wikipedia.org/wiki/Tor_%28network%29#Attacks_and_limitations"&gt;limitations&lt;/a&gt;, it can be possible to deanonymize
someone despite using it. Additionally, many websites are able to detect
connections from the Tor network and block them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What should I do instead?&lt;/strong&gt; If you want to use Tor to bypass censorship, it
is often better to use a trusted VPN provider, particularly if you need high
bandwidth (e.g. for streaming). If you want to use Tor to access a website
anonymously, Tor itself might not be enough to protect you. For example, if you
need to provide an email address or personal information, you can decline to
provide accurate information and use a &lt;a href="https://www.fastmail.com/features/masked-email/"&gt;masked email
address&lt;/a&gt;. A friend of mine
once used the alias "Nunya Biznes" &amp;#x1F978;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who should use it?&lt;/strong&gt; Tor should only be used by people who are experienced
users of security tools and understand its strengths and limitations. Tor also
is best used on a purpose-built system, such as &lt;a href="https://www.torproject.org/download/"&gt;Tor Browser&lt;/a&gt;
or Freedom of the Press Foundation's &lt;a href="https://securedrop.org/"&gt;SecureDrop&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;I want to learn more!&lt;/h1&gt;
&lt;p&gt;I hope you've found this guide to be a useful starting point. I always welcome
folks reaching out to me with questions, though I might take a little bit of
time to respond. You can always &lt;a href="mailto:security101@hashman.ca"&gt;email me&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If there's enough interest, I might cover the following topics in a future
post:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Threat modelling, which you can get started with by reading the &lt;a href="https://ssd.eff.org/module/your-security-plan"&gt;EFF's&lt;/a&gt; or
  &lt;a href="https://visionchangewin.org/wp-content/uploads/2024/11/VCW-Org-Safety-Planning-Pt-1-Risk-Assessment-2024.pdf"&gt;VCW's&lt;/a&gt; guides&lt;/li&gt;
&lt;li&gt;Browser addons for privacy, which &lt;a href="https://securityplanner.consumerreports.org/tool/reduce-online-tracking/"&gt;Consumer
  Reports&lt;/a&gt; has a tip for&lt;/li&gt;
&lt;li&gt;Secure DNS, which you can read more about &lt;a href="https://en.wikipedia.org/wiki/DNS_over_HTTPS"&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stay safe out there! &amp;#x1F512;&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>I am very sick</title><link href="https://hashman.ca/me-cfs/" rel="alternate"></link><published>2024-05-12T10:00:00-04:00</published><updated>2024-05-12T10:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2024-05-12:/me-cfs/</id><summary type="html">&lt;p&gt;In October 2022, I was diagnosed with ME/CFS. In February of last year, it got a lot worse.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have not been able to walk since February 18, 2023.&lt;/p&gt;
&lt;p&gt;When people ask me how I'm doing, this is the first thing that comes to mind.
"Well, you know, the usual, but also I still can't walk," I think to myself.&lt;/p&gt;
&lt;p&gt;If I dream at night, I often see myself walking or running. In conversation, if
I talk about going somewhere, I'll imagine walking there. Even though it's been
over a year, I remember walking to the bus, riding to see my friends, going out
for brunch, cooking community dinners.&lt;/p&gt;
&lt;p&gt;But these days, I can't manage going anywhere except by car, and I can't do the
driving, and I can't dis/assemble and load my chair. When I'm resting in bed
and follow a guided meditation, I might be asked to imagine walking up a
staircase, step by step. Sometimes, I do. Other times, I imagine taking a
little elevator in my chair, or wheeling up ramps.&lt;/p&gt;
&lt;p&gt;I feel like there is little I can say that can express the extent of what
this illness has taken from me, but it's worth trying. To an able-bodied
person, seeing me in a power wheelchair is usually "enough." One of my
acquaintances cried when they last saw me in person. But frankly, I love my
wheelchair. I am not "wheelchair-bound"&amp;mdash;I am bed-bound, and the
wheelchair gets me out of bed. My chair hasn't taken anything from me.&lt;/p&gt;
&lt;p&gt;&lt;center&gt;***&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;In October of 2022, I was diagnosed with myalgic encephalomyelitis.&lt;/p&gt;
&lt;p&gt;Scientists and doctors don't really know what myalgic encephalomyelitis (ME)
is. Diseases like it have been described for over 200 years.&lt;sup&gt;&lt;a href="https://en.wikipedia.org/wiki/History_of_ME/CFS#cite_ref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;
It primarily affects women between the ages of 10-39, and the primary symptom
is "post-exertional malaise" or PEM: debilitating, disproportionate fatigue
following activity, often delayed by 24-72 hours and not relieved by sleep.
That fatigue has earned the illness the misleading name of "Chronic Fatigue
Syndrome" or CFS, as though we're all just very tired all the time. But tired
people respond to exercise positively. People with ME/CFS do not.&lt;sup&gt;&lt;a href="https://workwellfoundation.org/wp-content/uploads/2023/01/Mateo-et-al-2020-Post-exertional-symptoms-distinguish-MECFS-from-HC.pdf"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Given the dearth of research and complete lack of on-label treatments, you may
think this illness is at least rare, but it is actually quite common: in the
United States, an estimated 836k-2.5m people&lt;sup&gt;&lt;a href="https://nap.nationalacademies.org/catalog/19012/beyond-myalgic-encephalomyelitischronic-fatigue-syndrome-redefining-an-illness"&gt;3&lt;/a&gt;&lt;/sup&gt; have ME/CFS. It is
frequently misdiagnosed, and it is estimated that as many as 90% of cases are
missed,&lt;sup&gt;&lt;a href="https://www.cdc.gov/me-cfs/about/index.html"&gt;4&lt;/a&gt;&lt;/sup&gt; due to mild or moderate symptoms that mimic other
diseases.  Furthermore, over half of Long COVID cases likely meet the
diagnostic criteria for ME,&lt;sup&gt;&lt;a href="https://www.nature.com/articles/s41598-023-48502-w"&gt;5&lt;/a&gt;&lt;/sup&gt; so these numbers have increased
greatly in recent years.  That is, ME is at least as common as rheumatoid
arthritis,&lt;sup&gt;&lt;a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8348893/"&gt;6&lt;/a&gt;&lt;/sup&gt; another delightful illness I have. But while any
doctor knows what rheumatoid arthritis is, not enough&lt;sup&gt;&lt;a href="https://www.meaction.net/2024/05/07/millionsmissing-week-is-here-teachmetreatme-in-action/"&gt;7&lt;/a&gt;&lt;/sup&gt; have heard
of "myalgic encephalomylitis."&lt;/p&gt;
&lt;p&gt;Despite a high frequency and disease burden, post-viral associated conditions
(PASCs) such as ME have been neglected for medical funding for
decades.&lt;sup&gt;&lt;a href="https://pubmed.ncbi.nlm.nih.gov/32568148/"&gt;8&lt;/a&gt;&lt;/sup&gt; Indeed, many people, including medical care workers,
find it hard to believe that after the acute phase of illness, severe symptoms
can persist. PASCs such as ME and Long COVID defy the typical narrative around
common illnesses. I was always told that if I got sick, I should expect to rest
for a bit, maybe take some medications, and a week or two later, I'd get
better, right? But I never got better.&lt;/p&gt;
&lt;p&gt;These are complex, multi-system diseases that do not neatly fit into the
Western medical system's specializations. I have seen nearly every specialty
because ME/CFS affects nearly every system of the body: cardiology, nephrology,
pulmonology, neurology, opthalmology, and, many, many more. You'd think they'd
hand out frequent flyer cards, or a medical passport with fun stamps, but nope.
Just hundreds of pages of medical records. And when I don't fit neatly into one
particular specialist's box, then I'm sent back to my primary care doctor to
regroup while we try to troubleshoot my latest concerning symptoms. "Sorry,
can't help you. Not my department."&lt;/p&gt;
&lt;p&gt;With little available medical expertise, a lot of my disease management has
been self-directed in partnership with primary care. I've read hundreds of
articles, papers, publications, CME material normally reserved for doctors.
It's truly out of necessity, and I'm certain I would be much worse off if I
lacked the skills and connections to do this; there are so few ME/CFS experts
in the US that there isn't one in my state or any adjacent state.&lt;sup&gt;&lt;a href="https://www.theatlantic.com/health/archive/2022/09/mecfs-chronic-fatigue-syndrome-doctors-long-covid/671518/"&gt;9&lt;/a&gt;&lt;/sup&gt;
So I've done a lot of my own work, much of it while barely being able to read.
(A text-to-speech service is a real lifesaver.) To facilitate managing my
illness, I've built a mental model of how my particular flavour of ME/CFS works
based on the available research I've been able to read and how I respond to
treatments. Here is my best attempt to explain it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;After a severe (non-COVID) infection, an ongoing interaction between my
  immune system and my metabolism have stopped my body from being able to do
  aerobic respiration.&lt;sup&gt;&lt;a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5161229/"&gt;10&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;I don't know why or how, but my mitochondria don't work properly
  anymore.&lt;sup&gt;&lt;a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7147788/"&gt;11&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;This means that if I use too much energy, my body isn't able to make enough
  energy to catch up, and I have severe symptoms over the next few days as my
  body tries to manage the consequences.&lt;/li&gt;
&lt;li&gt;Those symptoms aren't limited to fatigue: I've developed flu-like symptoms
  and even fevers, limbs so heavy they felt paralyzed, tachycardia in response
  to even the slightest activity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The best way I have learned to manage this is to prevent myself from doing
activities where I will exceed that aerobic threshold by wearing a heartrate
monitor,&lt;sup&gt;&lt;a href="https://www.cfsselfhelp.org/library/pacing-numbers-using-your-heart-rate-to-stay-inside-energy-envelope"&gt;12&lt;/a&gt;&lt;/sup&gt; but the amount of activity that permits in my current
state of health is laughably restrictive. Most days I'm unable to spend more
than one to two hours out of bed.&lt;/p&gt;
&lt;p&gt;Over time, this has meant worsening from a persistent feeling of tiredness all
the time and difficulty commuting into an office or sitting at a desk, to being
unable to sit at a desk for an entire workday even while working from home and
avoiding physically intense chores or exercise without really understanding
why, to being unable to leave my apartment for days at a time, and finally,
being unable to stand for more than a minute or two or walk.&lt;/p&gt;
&lt;p&gt;But it's not merely that I can't walk. Many folks in wheelchairs are able to
live excellent lives with adaptive technology. The problem is that I am so
fatigued, any activity can destroy my remaining quality of life. In my worst
moments, I've been unable to read, move my arms or legs, or speak aloud. Every
single one of my limbs burned, as though I had caught fire.  Food sat in my
stomach for hours, undigested, while my stomach seemingly lacked the energy to
do its job. I currently rely on family and friends for full-time caretaking,
plus a paid home health aide, as I am unable to prep meals, shower, or leave
the house independently. This assistance has helped me slowly improve from my
poorest levels of function.&lt;/p&gt;
&lt;p&gt;While I am doing better than I was at my worst, I've had to give up essentially
all of my hobbies with physical components. These include singing, cooking,
baking, taking care of my houseplants, cross-stitching, painting, and so on.
Doing any of these result in post-exertional malaise so I've had to stop; this
reduction of activity to prevent worsening the illness is referred to as
"pacing." I've also had to cut back essentially all of my volunteering and
work in open source; I am only cleared by my doctor to work 15h/wk (from bed)
as of writing.&lt;/p&gt;
&lt;p&gt;&lt;center&gt;***&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;CW: severe illness, death, and suicide (&lt;a href="#cw"&gt;skip this section&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The difficulty of living with a chronic illness is that there's no light at the
end of the tunnel. Some diseases have a clear treatment path: you take the
medications, you complete the procedures, you hit all the milestones, and then
you're done, perhaps with some long-term maintenance work. But with ME, there
isn't really an end in sight. The median duration of illness reported in one
1997 study was over 6 years, with some patients reporting 20 years of
symptoms.&lt;sup&gt;&lt;a href="https://pubmed.ncbi.nlm.nih.gov/11018368/"&gt;13&lt;/a&gt;&lt;/sup&gt; While a small number of patients spontaneously recover, and many
improve, the vast majority of patients are unable to regain their baseline
function.&lt;sup&gt;&lt;a href="https://me-pedia.org/wiki/Prognosis_for_myalgic_encephalomyelitis_and_chronic_fatigue_syndrome#Recovery_rates"&gt;14&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;My greatest fear since losing the ability to walk is getting worse still.
Because, while I already require assistance with nearly every activity of daily
living, there is still room for decline. The prognosis for extremely ill
patients is dismal, and many require feeding tubes and daily nursing care. This
may lead to life-threatening malnutrition;&lt;sup&gt;&lt;a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8070213/"&gt;15&lt;/a&gt;&lt;/sup&gt; a number of these extremely
severe patients have died, either due to medical neglect or suicide.&lt;sup&gt;&lt;a href="https://www.ncf-net.org/memorial"&gt;16&lt;/a&gt;&lt;/sup&gt;
Extremely severe patients cannot tolerate light, sound, touch, or cognitive
exertion,&lt;sup&gt;&lt;a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8544443/"&gt;17&lt;/a&gt;&lt;/sup&gt; and often spend most of their time lying flat in a darkened room
with ear muffs or an eye mask.&lt;sup&gt;&lt;a href="https://www.youtube.com/watch?v=vydgkCCXbTA"&gt;18&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;This is all to say, my prognosis is not great.&lt;/p&gt;
&lt;p&gt;But while I recognize that the odds aren't exactly in my favour, I am also damn
stubborn. (A friend once cheerfully described me as "stubbornly optimistic!") I
only get one shot at life, and I do not want to spend the entirety of it barely
able to perceive what's going on around me. So while my prognosis is uncertain,
there's lots of evidence that I can improve somewhat,&lt;sup&gt;&lt;a href="https://cfsselfhelp.org/library/will-i-get-better-tilting-odds-your-favor"&gt;19&lt;/a&gt;&lt;/sup&gt; and there's also lots of
evidence that I can live 20+ years with this disease. It's a bitter pill to
swallow, but it also means I might have the gift of time&amp;mdash;something that
not all my friends with severe complex illnesses have had.&lt;/p&gt;
&lt;p&gt;&lt;a name=cw&gt;&lt;/a&gt;I feel like I owe it to myself to do the best I can to improve;
to try to help others in a similar situation; and to enjoy the time that I
have. I already feel like my life has been moving in slow motion for the past 4
years&amp;mdash;there's no need to add more suffering. Finding joy, as much as I
can, every day, is essential to keep up my strength for this marathon. Even if
it takes 20 years to find a cure, I am convinced that the standard of care is
going to improve. All the research and advocacy that's been happening over the
past decade is plenty to feel hopeful about.&lt;sup&gt;&lt;a href="https://www.healthrising.org/?s=moment"&gt;20&lt;/a&gt;&lt;/sup&gt; Hope is a
discipline,&lt;sup&gt;&lt;a href="https://books.google.com/books/about/We_Do_This_Til_We_Free_Us.html?id=ShMIEAAAQBAJ"&gt;21&lt;/a&gt;&lt;/sup&gt; and I try to remind myself of this on the hardest
days.&lt;/p&gt;
&lt;p&gt;&lt;center&gt;***&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;I'm not entirely sure why I decided to write this. Certainly, today is
&lt;a href="https://www.cdc.gov/me-cfs/resources/awarenessday.html"&gt;International ME/CFS Awareness Day&lt;/a&gt;, and I'm hoping this post will
raise awareness in spaces that aren't often thinking about chronic illnesses.
But I think there is also a part of me that wants to share, reach out in some
way to the people I've lost contact with while I've been treading water,
managing the day to day of my illness. I experience this profound sense of
loss, especially when I think back to the life I had before. Everyone hits
limitations in what they can do and accomplish, but there is so little I can do
with the time and energy that I have. And yet, I understand even this precious
little could still be less. So I pace myself.&lt;/p&gt;
&lt;p&gt;Perhaps I can inspire you to take action on behalf of those of us too fatigued
to do the advocacy we need and deserve. Should you donate to a charity or
advocacy organization supporting ME/CFS research? In the US, there are many
excellent organizations, such as &lt;a href="https://www.meaction.net/millionsmissing-fundraiser-2024/"&gt;ME Action&lt;/a&gt;, the &lt;a href="https://www.omf.ngo/"&gt;Open Medicine
Foundation&lt;/a&gt;, &lt;a href="https://solvecfs.org/"&gt;SolveME&lt;/a&gt;, the &lt;a href="https://batemanhornecenter.org/donate/pay-form/"&gt;Bateman Horne Center&lt;/a&gt;, and the
&lt;a href="https://workwellfoundation.org/"&gt;Workwell Foundation&lt;/a&gt;. &lt;strong&gt;2025 Update:&lt;/strong&gt; I am &lt;strong&gt;doubly matching any
donations&lt;/strong&gt; through the end of May 2025 if you send me your receipts. I have
also launched individual fundraising campaigns for &lt;a href="https://meaction.funraise.org/fundraiser/elana-hashman"&gt;ME Action&lt;/a&gt; and
&lt;a href="https://openmedicinefoundation.crowdchange.co/50084"&gt;Open Medicine Foundation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But charitable giving only goes so far, and I think this problem deserves the
backing of more powerful organizations. Proportionate government funding and
support is desperately needed. It's critical for us to push
governments&lt;sup&gt;&lt;a href="https://www.nature.com/articles/d41586-023-03225-w"&gt;22&lt;/a&gt;&lt;/sup&gt; to provide the funding required for research that
will make an impact on patients' lives now. Many organizers are running
campaigns around the world, advocating for this investment. There is a natural
partnership between ME advocacy and Long COVID advocacy, for example, and we
have an opportunity to make a great difference to many people by pushing for
research and resources inclusive of all PASCs. Some examples I'm aware of
include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[US] A &lt;a href="https://www.sanders.senate.gov/press-releases/news-chairman-bernie-sanders-releases-long-covid-moonshot-legislative-proposal/"&gt;Long COVID "moonshot"&lt;/a&gt; effort, drafted in April 2024 by
  Senator Sanders. &lt;a href="https://www.usa.gov/elected-officials/"&gt;Contact your representatives&lt;/a&gt; and encourage them to
  support it. Ask them to ensure the effort &lt;strong&gt;includes support for ME/CFS&lt;/strong&gt; and
  other related conditions and PASCS. &lt;/li&gt;
&lt;li&gt;[Canada] National ME/FM Action recommended &lt;a href="http://www.mefmaction.com/index.php?option=com_content&amp;amp;view=article&amp;amp;id=577:federal-budget-consultation-2024&amp;amp;catid=68:canadiannews&amp;amp;Itemid=293"&gt;participation in public budget
  consultation&lt;/a&gt; processes and made a submission. Though the 2024
  consultation is closed, you can still &lt;a href="https://www.ourcommons.ca/Members/en"&gt;contact your MP&lt;/a&gt; to improve
  awareness and advocate for budgetary support. It may also be worth contacting 
  your MLA to advocate for better PASC care in provincial clinics.&lt;/li&gt;
&lt;li&gt;[UK] Action for ME is advocating for a &lt;a href="https://www.actionforme.org.uk/research-and-campaigns/campaigning-for-change/mecfs-delivery-plan/"&gt;cross-Government Delivery Plan for
  ME/CFS care&lt;/a&gt; in England. &lt;a href="https://www.parliament.uk/get-involved/contact-an-mp-or-lord/contact-your-mp/"&gt;Contact your MP&lt;/a&gt; and encourage them
  to support it.&lt;/li&gt;
&lt;li&gt;[Other] MEAction also regularly hosts government advocacy campaigns in the
  &lt;a href="https://www.meaction.net/take-action/usa-federa-agencies/"&gt;US&lt;/a&gt;, &lt;a href="https://www.meaction.net/countries/uk/"&gt;UK&lt;/a&gt;, and &lt;a href="https://www.meaction.net/countries/scotland/"&gt;Scotland&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But outside of collective organizing, there are a lot of sick individuals out
there that need help, too. Please, don't forget about us. We need you to visit
us, care for us, be our confidantes, show up as friends. There are a lot of
people who are very sick out here and need &lt;em&gt;your&lt;/em&gt; care.&lt;/p&gt;
&lt;p&gt;I'm one of them.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>I'm hosting a Bug Scrub for Kubernetes SIG Node</title><link href="https://hashman.ca/sig-node-bsp/" rel="alternate"></link><published>2021-06-17T11:20:00-04:00</published><updated>2021-06-17T11:20:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2021-06-17:/sig-node-bsp/</id><summary type="html">&lt;p&gt;I'm hosting a Kubernetes SIG Node bug scrub on Thursday, June 24th through Friday, June 25th, kicking off at 00:00 UTC on the 24th.&lt;/p&gt;</summary><content type="html">&lt;p&gt;It's been a long while since I &lt;a href="/nyc-bsp"&gt;last hosted a BSP&lt;/a&gt;, but 'tis the season.&lt;/p&gt;
&lt;p&gt;Kubernetes SIG Node will be holding a bug scrub on June 24-25, and this is a
great opportunity for you to get involved if you're interested in contributing
to Kubernetes or SIG Node!&lt;/p&gt;
&lt;p&gt;We will be hosting a global event with region captains for all timezones. I am
one of the NASA captains (~17:00-01:00 UTC) and I'll be leading the kickoff. We
will be working on Slack and Zoom. I hope you'll be able to drop in!&lt;/p&gt;
&lt;h3&gt;Details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Date:&lt;/strong&gt; Thursday, June 24 through Friday, June 25&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start:&lt;/strong&gt; 00:00 UTC June 24&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End:&lt;/strong&gt; 23:59 UTC June 25&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sign up:&lt;/strong&gt; Participants do not have to sign up, just show up!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slack room:&lt;/strong&gt; &lt;a href="https://kubernetes.slack.com/archives/C02491CNJKZ"&gt;#sig-node-bug-scrub&lt;/a&gt; on Kubernetes Slack&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docs:&lt;/strong&gt; See the &lt;a href="https://hackmd.io/@sig-node-bug-scrub/S1gQnDbjO"&gt;HackMD docs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email:&lt;/strong&gt; See the &lt;a href="https://groups.google.com/g/kubernetes-dev/c/w2ghO4ihje0"&gt;kubernetes-dev mailing list&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;I'm an existing contributor, what should I work on?&lt;/h2&gt;
&lt;p&gt;Work on triaging and closing SIG Node bugs. We have a lot of bugs!!&lt;/p&gt;
&lt;p&gt;The goal of our event is to categorize, clean up, and resolve some of the &lt;a href="https://github.com/kubernetes/kubernetes/issues?q=is%3Aopen+is%3Aissue+label%3Asig%2Fnode"&gt;450+
issues in k/k for SIG Node&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://hackmd.io/@sig-node-bug-scrub/S1gQnDbjO"&gt;event docs&lt;/a&gt; for more instructions.&lt;/p&gt;
&lt;h2&gt;I'm a new contributor and want to join but I have no idea what I'm doing!&lt;/h2&gt;
&lt;p&gt;At some point, that was all of us!&lt;/p&gt;
&lt;p&gt;This is a great opportunity to get involved if you've never contributed to
Kubernetes. We'll have dedicated mentors available to coordinate and help out
new contributors.&lt;/p&gt;
&lt;p&gt;If you've never contributed to Kubernetes before, I recommend you check out the
&lt;a href="https://github.com/kubernetes/community/blob/master/contributors/guide/README.md"&gt;Getting Started&lt;/a&gt;
and &lt;a href="https://github.com/kubernetes/community/blob/master/contributors/devel/README.md"&gt;Contributor Guide&lt;/a&gt;
resources in advance of the event. You will want to ensure you've signed the
&lt;a href="https://github.com/kubernetes/community/blob/master/CLA.md"&gt;contributor license agreement&lt;/a&gt; (CLA).&lt;/p&gt;
&lt;p&gt;Remember, you &lt;strong&gt;don't have to code&lt;/strong&gt; to make valuable contributions! Triaging
the bug tracker is a great example of this.&lt;/p&gt;
&lt;h2&gt;See you there!&lt;/h2&gt;
&lt;p&gt;Happy hacking.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Easy risotto</title><link href="https://hashman.ca/risotto/" rel="alternate"></link><published>2020-12-16T20:00:00-05:00</published><updated>2020-12-16T20:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2020-12-16:/risotto/</id><summary type="html">&lt;p&gt;Risotto, 45 minutes from start to finish?! Yes, it &lt;em&gt;is&lt;/em&gt; possible.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I have a secret: risotto doesn't &lt;em&gt;have&lt;/em&gt; to involve standing over a pot,
stirring for 30 minutes. There is a better way.&lt;/p&gt;
&lt;p&gt;I've made risotto using the "stir 5ever" method and frankly this one is half
the work and just as good. I took inspiration from &lt;a href="https://www.seriouseats.com/recipes/2011/10/how-to-make-perfect-risotto-recipe.html"&gt;Kenji
Lopez-Alt&lt;/a&gt;, who describes how you can make risotto with only a few
minutes of stirring at the end! Yes, this is a secret too good to keep to
myself.&lt;/p&gt;
&lt;p&gt;The linked recipe is too rich for a weeknight dinner, at least for my tastes,
so I've included my typical modifications below, which omits the heavy cream. I
usually make mushroom risotto, because all the ingredients are long-lived
pantry ingredients, which means I can make this on a whim without having to
grocery shop!&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-conversation="none" data-lang="en" data-dnt="true"&gt;
  &lt;p lang="und" dir="ltr"&gt;👀 &lt;a href="https://t.co/9gD4OGLZDs"&gt;pic.twitter.com/9gD4OGLZDs&lt;/a&gt;
  &lt;/p&gt;&amp;mdash; e. hashman (@ehashdn)
  &lt;a href="https://twitter.com/ehashdn/status/1339400747721478144?ref_src=twsrc%5Etfw"&gt;December 17, 2020&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;h2&gt;Mushroom risotto&lt;/h2&gt;
&lt;p&gt;Serves 3 as a main course. Active time: 25m. Total time: 45m.&lt;/p&gt;
&lt;p&gt;Ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1oz (28g) dried mushrooms, such as porcini (or morels!)&lt;/li&gt;
&lt;li&gt;3 &amp;frac12; cups chicken or vegetable stock&lt;/li&gt;
&lt;li&gt;1 &amp;frac12; cups short-grained rice (I use arborio)&lt;/li&gt;
&lt;li&gt;&amp;frac12; cup white wine&lt;/li&gt;
&lt;li&gt;2 tbsp olive oil&lt;/li&gt;
&lt;li&gt;2 tbsp unsalted butter&lt;/li&gt;
&lt;li&gt;4 cloves garlic, minced&lt;/li&gt;
&lt;li&gt;1 small onion, small diced&lt;/li&gt;
&lt;li&gt;3oz (85g) grated Parmesan cheese&lt;/li&gt;
&lt;li&gt;herbs for garnish (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recipe:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Leave mushrooms to rehydrate in 1 cup of hot water for at least 10 minutes.&lt;/li&gt;
&lt;li&gt;Set a wide saucepan (about 3.5qts) or skillet on medium heat.&lt;/li&gt;
&lt;li&gt;Mix stock and wine for a total of 4 cups. You can used homemade stock (the
   best), boxed, or reconstitute from bouillon (my usual). If you use bouillon, 
   I find you get the best flavour if you use a mix, so I tend to use half
   "no-chicken" and half "organic chicken" of the Better than Bouillon brand.
   Let this cool if you used boiling water; you don't want it to be too hot.&lt;/li&gt;
&lt;li&gt;Mix the rice and stock in a large bowl, agitating it to release the starch.
   Reserve stock and set the rice in a strainer to drain.&lt;/li&gt;
&lt;li&gt;Small dice an onion. Add olive oil and butter to the pan, and then add
   the onion. Cook the onion until it's translucent, but don't brown it.&lt;/li&gt;
&lt;li&gt;Increase the heat to high and add the rice to the pan to toast until it
   becomes a little bit brown, stirring occasionally, about 3-4 minutes. Set a
   timer so it doesn't burn &amp;#x1F600;&lt;/li&gt;
&lt;li&gt;Meanwhile, drain the mushrooms, making sure you reserve the broth. Chop
   mushrooms and mince the garlic. Once the rice is toasted, add mushrooms and
   garlic and stir.&lt;/li&gt;
&lt;li&gt;Stir the reserved stock. Add all of the mushroom liquid and all but 1 cup of 
   the starchy stock to the pan. Bring to a boil.&lt;/li&gt;
&lt;li&gt;Once it has reached a boil, cover, reduce to the lowest heat, and allow the
   rice to simmer undisturbed for 10 minutes. In the meantime, you can grate
   the cheese.&lt;/li&gt;
&lt;li&gt;After 10 minutes, stir the rice once, shake the pan to ensure it is level,
    and return to the heat for 10 more minutes. Sit back, relax, and bask in the
    very little stirring you are doing.&lt;/li&gt;
&lt;li&gt;At this point, the rice should be nearly cooked. Give it a stir, and add
    the remaining cup of broth. Stir until fully incorporated, turn the heat up
    to high, and cook until the risotto reaches your preferred consistency. I
    like mine rather thick.&lt;/li&gt;
&lt;li&gt;Once the rice is fully cooked, turn off the heat and stir in the grated
    cheese a bit at a time, reserving some for garnish. Taste, and season with
    salt and pepper.&lt;/li&gt;
&lt;li&gt;Garnish with the grated cheese, and perhaps some herbs. Serve and enjoy!&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Variations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;No mushrooms:&lt;/strong&gt; Okay, okay, you hate mushrooms! Sorry! You can leave them
out. Don't bother with the mushrooms, and add broth to make up for the lost
liquid.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mushroom &lt;em&gt;lover&lt;/em&gt;:&lt;/strong&gt; Alternatively, if you &lt;em&gt;love&lt;/em&gt; mushrooms and you have fresh
ones available, use &amp;frac13; to &amp;frac12; a pound (150-225g) chopped fresh
mushrooms instead of dried. Add them at the same time you add the onions to
ensure all the liquid cooks off.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Milanese, with stuff:&lt;/strong&gt; One of my favourite variations on this dish is a
version with shrimp, asparagus, and saffron. Leave the mushrooms out, increase
the wine to &amp;frac34; or even 1 cup (seafood likes a little extra acidity),
ensure you have a total of 5 cups of broth, and add a few strands of saffron.
Chop asparagus and shrimp, season with salt and pepper, sauté them with some
butter or olive oil in a separate pan so they don't overcook, and fold them in
at the very end, after you've added the cheese.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I MUST SUFFER:&lt;/strong&gt; This was too easy? Want to stir more??? Fine, &lt;a href="https://youtu.be/MSI4ZHVSatw"&gt;have it your
$*!#ing way.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'm sure you can be creative and come up with something on your own...&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Three talks at DebConf 2020</title><link href="https://hashman.ca/debconf-2020/" rel="alternate"></link><published>2020-09-05T00:00:00-04:00</published><updated>2020-09-05T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2020-09-05:/debconf-2020/</id><summary type="html">&lt;p&gt;I spoke on three panels at DebConf 2020 ("DebConf at Home"). Here are the video recordings as well as brief summaries of each appearance.&lt;/p&gt;</summary><content type="html">&lt;p&gt;This year has been a really unusual one for in-person events like conferences.
I had already planned to take this year off from travel for the most part,
attending just a handful of domestic conferences. But the pandemic has thrown
those plans into chaos; I do not plan to attend large-scale in-person events
until July 2021 at the earliest, per my employer's guidance.&lt;/p&gt;
&lt;p&gt;I've been really sad to have turned down multiple speaking invitations this
year. To try to set expectations, I added a note to my &lt;a href="/talks"&gt;Talks&lt;/a&gt; page
that indicates I will not be writing any new talks for 2020, but am happy to
join panels or reprise old talks.&lt;/p&gt;
&lt;p&gt;And somehow, with all that background, I still ended up giving &lt;em&gt;three&lt;/em&gt; talks at
DebConf 2020 this year. In part, I think it's because this is the first DebConf
I've been able to attend since 2017, and I was so happy to have the
opportunity! I took time off work to give myself enough space to focus on the
conference. International travel is very difficult for me, so DebConf is
generally challenging if not impossible for me to attend.&lt;/p&gt;
&lt;h2&gt;A panel a day keeps the FTP Team away?&lt;/h2&gt;
&lt;p&gt;On Thursday, August 27th, I spoke on the &lt;a href="https://debconf20.debconf.org/talks/46-leadership-in-debian-bofpanel/"&gt;Leadership in Debian&lt;/a&gt;
panel, where I discussed some of the challenges leadership in the project must
face, including an appropriate response to the BLM movement and sustainability
for volunteer positions that require unsustainable hours (such as DPL).&lt;/p&gt;
&lt;div style="text-align: center"&gt;
 &lt;video width="600" height="333" controls&gt;
  &lt;source src="https://meetings-archive.debian.net/pub/debian-meetings/2020/DebConf20/46-leadership-in-debian-bofpanel.webm"
          type="video/webm"&gt;
  Your browser does not support the video tag.
 &lt;/video&gt; 
&lt;/div&gt;

&lt;p&gt;On Friday, August 28th, I hosted the &lt;a href="https://debconf20.debconf.org/talks/33-clojure-packaging-team-bof/"&gt;Debian Clojure BoF&lt;/a&gt;, attended by
members of the Clojure and Puppet teams. The Puppet team is working to package
the latest versions of Puppet Server/DB, which involve significant Clojure
components, and I am doing my best to help.&lt;/p&gt;
&lt;div style="text-align: center"&gt;
 &lt;video width="600" height="333" controls&gt;
  &lt;source src="https://meetings-archive.debian.net/pub/debian-meetings/2020/DebConf20/33-clojure-packaging-team-bof.webm"
          type="video/webm"&gt;
  Your browser does not support the video tag.
 &lt;/video&gt; 
&lt;/div&gt;

&lt;p&gt;On Saturday, August 29th, I spoke on the &lt;a href="https://debconf20.debconf.org/talks/16-meet-the-technical-committee/"&gt;Meet the Technical Committee&lt;/a&gt;
panel. The Committee presented a number of proposals for improving how we work
within the project. I was responsible for presenting our first proposal on
allowing folks to engage the committee privately.&lt;/p&gt;
&lt;div style="text-align: center"&gt;
 &lt;video width="600" height="333" controls&gt;
  &lt;source src="https://meetings-archive.debian.net/pub/debian-meetings/2020/DebConf20/16-meet-the-technical-committee.webm"
          type="video/webm"&gt;
  Your browser does not support the video tag.
 &lt;/video&gt; 
&lt;/div&gt;</content><category term="talks"></category></entry><entry><title>My term at the Open Source Initiative thus far</title><link href="https://hashman.ca/osi-2020/" rel="alternate"></link><published>2020-09-02T12:15:00-04:00</published><updated>2020-09-02T12:15:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2020-09-02:/osi-2020/</id><summary type="html">&lt;p&gt;Reflecting on 18 months serving as a Director for the Open Source Initiative.&lt;/p&gt;</summary><content type="html">&lt;p&gt;When I ran for the OSI board in early 2019, I &lt;a href="/osi"&gt;set three goals for
myself&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grow the OSI's membership, and build a more representative organization.&lt;/li&gt;
&lt;li&gt;Defend the Open Source Definition and FOSS commons.&lt;/li&gt;
&lt;li&gt;Define the future of open source, as part of the larger community.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that the OSI has announced &lt;a href="https://opensource.org/node/1080"&gt;hiring an interim General Manager&lt;/a&gt;, I
thought it would be a good time to publicly reflect on what I've accomplished
and what I'd like to see next.&lt;/p&gt;
&lt;p&gt;As I promised in &lt;a href="https://wiki.opensource.org/bin/Main/OSI%20Board%20of%20Directors/Board%20Member%20Elections/Hashman2019"&gt;my campaign pitch&lt;/a&gt;, I aim to be publicly
accountable :)&lt;/p&gt;
&lt;h2&gt;Growing the OSI's membership&lt;/h2&gt;
&lt;p&gt;I have served as our Membership Committee Chair since the May 2019 board
meeting, tasked with devising and supervising strategy to increase membership
and deliver value to members.&lt;/p&gt;
&lt;p&gt;As part of my election campaign last year, I signed up over 50 new individual
members. Since May 2019, we've seen strong 33% growth of individual members, to
reach a new all-time high over 600 (638 when I last checked).&lt;/p&gt;
&lt;p&gt;I see the OSI as a relatively neutral organization that occupies a unique
position to build bridges among organizations within the FOSS ecosystem. In
order to facilitate this, we need a representative membership, and we need to
engage those members and provide forums for cross-pollination. As Membership
Committee Chair, I have been running quarterly video calls on Jitsi for our
affiliate members, where we can share updates between many global organizations
and discuss challenges we all face.&lt;/p&gt;
&lt;p&gt;But it's not enough just to hold the discussion; we also need to bring fresh
new voices into the conversation. Since I've joined the board, I'm thrilled to
say that 16 new affiliate members joined (in chronological order) for a total
of 81:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.brandeis.edu/"&gt;Brandeis University&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.osmfoundation.org/wiki/Main_Page"&gt;OpenStreetMap Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://todogroup.org/"&gt;TODO Group&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://osf.dev/"&gt;OpenStack Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nwtime.org/"&gt;Network Time Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sourcefabric.org/"&gt;Sourcefabric&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ocf.tw/"&gt;Open Culture Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fuss.bz.it/"&gt;FUSS Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fossasia.org/"&gt;FOSSASIA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openpreservation.org/"&gt;Open Preservation Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oscafrica.org/"&gt;Open Source Community Africa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.openforumeurope.org/"&gt;Open Forum Europe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnome.org/foundation/"&gt;GNOME Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjsf.org/"&gt;OpenJS Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oasis-open.org/"&gt;OASIS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openuk.uk/"&gt;OpenUK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was also excited to run a survey of the OSI's individual and affiliate
membership to help inform the future of the organization that received 58
long-form responses. The survey has been accepted by the board at our August
meeting and should be released publicly soon!&lt;/p&gt;
&lt;h2&gt;Defending the Open Source Definition&lt;/h2&gt;
&lt;p&gt;When I joined the board, the first committee I joined was the License
Committee, which is responsible for running the &lt;a href="https://opensource.org/approval"&gt;licence review process&lt;/a&gt;,
making recommendations on new licenses, and maintaining our existing licenses.&lt;/p&gt;
&lt;p&gt;Over the past year, under &lt;a href="https://opensource.org/docs/board-annotated#PamelaChestek"&gt;Pamela Chestek&lt;/a&gt;'s leadership as Chair, the full
board has approved the following licenses (with SPDX identifiers in brackets)
on the recommendation of the License Committee:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2019-June/004247.html"&gt;LBNL BSD License&lt;/a&gt; (BSD-3-Clause-LBNL)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2019-September/004416.html"&gt;OpenLDAP Public License Version 2.8&lt;/a&gt; (OLDAP-2.8)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lists.opensource.org/pipermail/license-review_lists.opensource.org/2020-February/004694.html"&gt;CAL Beta 4&lt;/a&gt; (CAL-1.0)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2020-February/004695.html"&gt;Mulan PSL v2&lt;/a&gt; (MulanPSL-2.0)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2020-April/004807.html"&gt;BSD 1 Clause&lt;/a&gt; (BSD-1-Clause)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2020-May/004841.html"&gt;PHP License 3.01&lt;/a&gt; (PHP-3.01)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2020-June/004890.html"&gt;The Unlicense&lt;/a&gt; (Unlicense)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2020-August/004915.html"&gt;MIT No Attribution&lt;/a&gt; (MIT-0)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We withheld approval of the following licenses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2019-August/004280.html"&gt;CAL v1.0 (initial draft)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lists.opensource.org/pipermail/license-review_lists.opensource.org/2020-January/004645.html"&gt;Vaccine License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I've also worked to define the scope of work for hiring someone to &lt;a href="https://wiki.opensource.org/bin/LicenseReviewToolRequirements/"&gt;improve
our license review&lt;/a&gt; process, which we have an &lt;a href="https://opensource.org/node/1078"&gt;open RFP&lt;/a&gt; for!&lt;/p&gt;
&lt;h2&gt;Chopping wood and carrying water&lt;/h2&gt;
&lt;p&gt;I joined the OSI with the goal of improving an organization I didn't think was
performing up to its potential. Its membership and board were not
representative of the wider open source community, its messaging felt outdated,
and it seemed to be failing to rise to today's challenges for FOSS.&lt;/p&gt;
&lt;p&gt;But before one can rise to meet these challenges, you need a strong foundation.
The OSI needed the organizational structure, health, and governance in order to
address such questions. Completing that work is essential, but not exactly
glamourous&amp;mdash;and it's a place that I thrive. Honestly, I don't (yet?) want
to be the public face of the organization, and I apologize to those who've
missed me at events like FOSDEM.&lt;/p&gt;
&lt;p&gt;I want to talk a little about some of my behind-the-scenes activities that I've
completed as part of my board service:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pushing for organizational &lt;a href="https://en.wikipedia.org/wiki/Directors_and_officers_liability_insurance"&gt;D&amp;amp;O and liability insurance&lt;/a&gt;, which we
  obtained in July 2020&lt;/li&gt;
&lt;li&gt;Recruiting and encouraging new board members: I helped recruit both our
  appointed board members, &lt;a href="https://opensource.org/docs/board-annotated#DebBryant"&gt;Deb Bryant&lt;/a&gt; and &lt;a href="https://opensource.org/docs/board-annotated#TracyHinds"&gt;Tracy Hinds&lt;/a&gt;,
  who now serve as officers, and &lt;a href="https://twitter.com/ehashdn/status/1233471774660136962"&gt;endorsed&lt;/a&gt;
  &lt;a href="https://opensource.org/docs/board-annotated#MeganByrd-Sanicki"&gt;Megan Byrd-Sanicki&lt;/a&gt;'s candidacy, also a board officer&lt;/li&gt;
&lt;li&gt;Recruiting and interviewing a new &lt;a href="https://opensource.org/node/1080"&gt;interim General Manager&lt;/a&gt;, Deb
  Nicholson&lt;/li&gt;
&lt;li&gt;Forming an Incubator Project Working Group to determine graduation criteria
  for OSI Incubator Projects and serving as &lt;a href="https://snowdrift.coop/"&gt;Snowdrift.coop&lt;/a&gt;'s board
  sponsor&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of this work is intended to improve the organization's health and provide
it with an excellent foundation for its mission.&lt;/p&gt;
&lt;h2&gt;Defining the future of open source&lt;/h2&gt;
&lt;p&gt;Soon after I was elected to the board, I gave a talk at Brooklyn.js entitled
&lt;a href="https://github.com/brooklynjs/brooklynjs.github.io/issues/557"&gt;"The Future of Open Source."&lt;/a&gt; In this presentation, I pondered about the
history and future of the free and open source software movement, and the
ethical questions we must face.&lt;/p&gt;
&lt;p&gt;In my election campaign, I wrote "Software licenses are a means, not an end, to
open source software. Focusing on licensing is necessary but not sufficient to
ensure a vibrant, thriving open source community. Focus on licensing to the
exclusion of other serious community concerns is to our collective detriment."&lt;/p&gt;
&lt;p&gt;My primary goal for my first term on the board was to ensure the OSI would be
positioned to answer wider questions about the open source community and its
future beyond licenses. Over the past two months, I supported Megan
Byrd-Sanicki's suggestion to hold (and then participated in, with the rest of
the board) organizational strategy sessions to facilitate our long-term
planning. My contribution to help inform these sessions was providing the
member survey on behalf of the Membership Committee.&lt;/p&gt;
&lt;p&gt;Now, I think we are much better equiped to face the hard questions we'll have
to tackle. In my opinion, the Open Source Initiative is better positioned than
ever to answer them, and I can't wait to see what the future brings.&lt;/p&gt;
&lt;p&gt;Hope to see you at our first &lt;a href="https://opensource.org/StateOfTheSource"&gt;State of the Source&lt;/a&gt; conference next week!&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Presenter mode in LibreOffice Impress without an external display</title><link href="https://hashman.ca/libreoffice/" rel="alternate"></link><published>2020-05-27T21:15:00-04:00</published><updated>2020-05-27T21:15:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2020-05-27:/libreoffice/</id><summary type="html">&lt;p&gt;LibreOffice impress, for some reason, does not support presenter mode with a single display. So I found a workaround.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I typically use LibreOffice Impress for my talks, much to some folks' surprise.
Yes, you &lt;em&gt;can&lt;/em&gt; make slides look okay with free software! But there's one
annoying caveat that has bothered me for ages.&lt;/p&gt;
&lt;p&gt;Impress makes it nearly impossible to enter presenter mode with a single
display, while also displaying slides. I have never understood this limitation,
but it's existed for a minimum of &lt;a href="https://bugs.documentfoundation.org/show_bug.cgi?id=62179"&gt;&lt;em&gt;seven years&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I've tried all sorts of workarounds over the years, including &lt;a href="https://bz.apache.org/ooo/show_bug.cgi?id=121873#c12"&gt;a macro that
forces LibreOffice into presenter mode&lt;/a&gt;, which I never was able to
figure out how to reverse once I ran it...&lt;/p&gt;
&lt;p&gt;This has previously been an annoyance but never posed a big problem, because
when push came to shove I could leave my house and use an external monitor or
screen when presenting at meetups. But now, everything's virtual, I'm in
lockdown indefinitely, and I don't have another display available at home. And
about 8 hours before speaking at a meetup today, I realized I didn't have a way
to share my slides while seeing my speaker notes. Uh oh.&lt;/p&gt;
&lt;p&gt;So I got this stupid idea.&lt;/p&gt;
&lt;p&gt;...why don't I just placate LibreOffice with a FAKE display?&lt;/p&gt;
&lt;h2&gt;Virtual displays with &lt;code&gt;xrandr&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;My GPU had this capability innately, it turns out, if I could just whisper the
right incantations to unlock its secrets:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ehashman@red-dot:~$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/usr/share/X11/xorg.conf.d/20-intel.conf&lt;span class="w"&gt; &lt;/span&gt;
Section&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Device&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Identifier&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;intelgpu0&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Driver&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;intel&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Option&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;VirtualHeads&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
EndSection
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After restarting X to allow this newly created config to take effect, I now
could see two new virtual displays available for use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ehashman@red-dot:~$&lt;span class="w"&gt; &lt;/span&gt;xrandr
Screen&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;minimum&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;current&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3840&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1080&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;maximum&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32767&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32767&lt;/span&gt;
eDP1&lt;span class="w"&gt; &lt;/span&gt;connected&lt;span class="w"&gt; &lt;/span&gt;primary&lt;span class="w"&gt; &lt;/span&gt;1920x1080+0+0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;left&lt;span class="w"&gt; &lt;/span&gt;inverted&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;310mm&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;170mm
&lt;span class="w"&gt;   &lt;/span&gt;1920x1080&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;.01*+&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;59&lt;/span&gt;.93&lt;span class="w"&gt;  &lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;...
&lt;span class="w"&gt;   &lt;/span&gt;640x360&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;59&lt;/span&gt;.84&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;59&lt;/span&gt;.32&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;.00&lt;span class="w"&gt;  &lt;/span&gt;
DP1&lt;span class="w"&gt; &lt;/span&gt;disconnected&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;left&lt;span class="w"&gt; &lt;/span&gt;inverted&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="o"&gt;)&lt;/span&gt;
DP2&lt;span class="w"&gt; &lt;/span&gt;disconnected&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;left&lt;span class="w"&gt; &lt;/span&gt;inverted&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="o"&gt;)&lt;/span&gt;
HDMI1&lt;span class="w"&gt; &lt;/span&gt;disconnected&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;left&lt;span class="w"&gt; &lt;/span&gt;inverted&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="o"&gt;)&lt;/span&gt;
HDMI2&lt;span class="w"&gt; &lt;/span&gt;disconnected&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;left&lt;span class="w"&gt; &lt;/span&gt;inverted&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="o"&gt;)&lt;/span&gt;
VIRTUAL1&lt;span class="w"&gt; &lt;/span&gt;disconnected&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;left&lt;span class="w"&gt; &lt;/span&gt;inverted&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="o"&gt;)&lt;/span&gt;
VIRTUAL2&lt;span class="w"&gt; &lt;/span&gt;disconnected&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;normal&lt;span class="w"&gt; &lt;/span&gt;left&lt;span class="w"&gt; &lt;/span&gt;inverted&lt;span class="w"&gt; &lt;/span&gt;right&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="w"&gt; &lt;/span&gt;y&lt;span class="w"&gt; &lt;/span&gt;axis&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nice. Now, to actually use it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ehashman@red-dot:~$&lt;span class="w"&gt; &lt;/span&gt;xrandr&lt;span class="w"&gt; &lt;/span&gt;--addmode&lt;span class="w"&gt; &lt;/span&gt;VIRTUAL1&lt;span class="w"&gt; &lt;/span&gt;1920x1080
ehashman@red-dot:~$&lt;span class="w"&gt; &lt;/span&gt;xrandr&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="w"&gt; &lt;/span&gt;VIRTUAL1&lt;span class="w"&gt; &lt;/span&gt;--mode&lt;span class="w"&gt; &lt;/span&gt;1920x1080&lt;span class="w"&gt; &lt;/span&gt;--right-of&lt;span class="w"&gt; &lt;/span&gt;eDP1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And indeed, after running these commands, I found myself with a virtual
display, very happy to black hole all my windows, available to the imaginary
right of my laptop screen.&lt;/p&gt;
&lt;p&gt;This allowed me to mash that "Present" button in LibreOffice and get my
presenter notes on my laptop display, while putting my actual slides in a
virtual time-out that I could still screenshare!&lt;/p&gt;
&lt;p&gt;Wouldn't it be nice if LibreOffice just fixed the actual bug? &amp;#x1F937;&lt;/p&gt;
&lt;h2&gt;Well, actually...&lt;/h2&gt;
&lt;p&gt;I must forgive myself for my stage panic. The talk ended up going great, and
the immediate problem was solved. But it turns out this bug &lt;em&gt;has&lt;/em&gt; been
addressed upstream! It's just... not well-documented.&lt;/p&gt;
&lt;p&gt;A couple years ago, there was &lt;a href="https://ask.libreoffice.org/en/question/166523/is-it-possible-to-enter-the-presenter-console-in-impress-without-external-monitor/"&gt;a forum post on ask.libreoffice.org&lt;/a&gt; that
featured this exact question, and a solution was provided!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yes, use Open Expert Configuration via &lt;code&gt;Tools &amp;gt; Options &amp;gt; LibreOffice &amp;gt;
Advanced.&lt;/code&gt; Search for &lt;code&gt;StartAlways&lt;/code&gt;. You should get a node
&lt;code&gt;org.openoffice.Office.PresenterScreen&lt;/code&gt; with line &lt;code&gt;Presenter&lt;/code&gt;. Double-click that
line to toggle the boolean value to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I tested this out locally and... yeah that works. But it turns out the bug from
2013 had not been updated with this solution &lt;a href="https://bugs.documentfoundation.org/show_bug.cgi?id=62179#c12"&gt;until just a few months
ago&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are very limited search results for this configuration property. I wish
this was much better documented. But so it goes with free software; here's a
hack and a real solution as we all try to improve things :)&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Beef and broccoli</title><link href="https://hashman.ca/beef-broccoli/" rel="alternate"></link><published>2020-05-25T19:30:00-04:00</published><updated>2020-05-25T19:30:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2020-05-25:/beef-broccoli/</id><summary type="html">&lt;p&gt;This is my recipe for Chinese-influenced beef and broccoli.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Beef and broccoli is one of my favourite easy weeknight meals. It's savoury,
it's satisfying, it's mercifully quick, and so, so delicious.&lt;/p&gt;
&lt;p&gt;The recipe here is based on &lt;a href="https://www.simplyrecipes.com/recipes/broccoli_beef/"&gt;this
one&lt;/a&gt; but with a few
simplifications and modifications. The ingredients are basically the same, but
the technique is a little different. Oh, and I include some fermented black
beans because they're yummy :3&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;&lt;p lang="en" dir="ltr"&gt;
Made 🥩 and 🥦 &lt;a
href="https://t.co/cSpyA3hzP6"&gt;pic.twitter.com/cSpyA3hzP6&lt;/a&gt;&lt;/p&gt;&amp;mdash; e.
hashman (@ehashdn) &lt;a
href="https://twitter.com/ehashdn/status/1252404252795797504?ref_src=twsrc%5Etfw"&gt;April
21, 2020&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async
src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;h2&gt;&amp;#x1F969; and &amp;#x1F966;&lt;/h2&gt;
&lt;p&gt;Serves 3. Active time: 20-30m. Total time: 30m.&lt;/p&gt;
&lt;p&gt;Ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;frac34; lb steak, thinly sliced (leave it in the freezer for ~30m to make
  slicing easier)&lt;/li&gt;
&lt;li&gt;&amp;frac34; lb broccoli florets&lt;/li&gt;
&lt;li&gt;3 large cloves garlic, chopped&lt;/li&gt;
&lt;li&gt;1 teaspoon fermented black beans, rinsed and chopped (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the marinade:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 teaspoon soy sauce&lt;/li&gt;
&lt;li&gt;1 teaspoon shaoxing rice wine or dry sherry&lt;/li&gt;
&lt;li&gt;&amp;frac12; teaspoon corn starch&lt;/li&gt;
&lt;li&gt;&amp;frac18; teaspoon ground black pepper&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the sauce:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 tablespoons oyster sauce&lt;/li&gt;
&lt;li&gt;2 teaspoons soy sauce&lt;/li&gt;
&lt;li&gt;1 teaspoon shaoxing rice wine or dry sherry&lt;/li&gt;
&lt;li&gt;&amp;frac14; cup chicken broth (I use &lt;a href="https://www.betterthanbouillon.com/"&gt;Better than
  Bouillon&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;2 tablespoons water&lt;/li&gt;
&lt;li&gt;1 teaspoon corn starch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the rice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;frac34; cup white medium-grain rice (I use calrose)&lt;/li&gt;
&lt;li&gt;1&amp;frac14; cup water&lt;/li&gt;
&lt;li&gt;large pinch of salt&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recipe:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Begin by preparing the rice: combine rice, water, and salt in a small
   saucepan and bring to a boil. Once it reaches a boil, cover and reduce to a
   simmer for 20 minutes. Then turn off the heat and let it rest.&lt;/li&gt;
&lt;li&gt;Mix the marinade in a bowl large enough to hold the meat.&lt;/li&gt;
&lt;li&gt;Thinly slice the beef. Place slices in the marinade bowl and toss to evenly
   coat.&lt;/li&gt;
&lt;li&gt;Start heating a wok or similar pan on medium-high to high heat. This will
   ensure you get a good sear.&lt;/li&gt;
&lt;li&gt;Prep the garlic, black beans, and broccoli. If you use frozen broccoli, you
   can save some time here :)&lt;/li&gt;
&lt;li&gt;Combine the ingredients for the sauce and mix well to ensure the corn starch
   doesn't form any lumps.&lt;/li&gt;
&lt;li&gt;By this point the beef should have been marinating for about 10-15m. Add a
   tablespoon of neutral cooking oil (like canola or soy) to the meat, give it
   one more toss to ensure it's thoroughly coated, then add a layer of meat to
   the dry pan. You may need to sear in batches. On high heat, cooking will
   take 1-2 minutes per side, ensuring each is nicely browned. Once the strips
   are cooked, remove from the pan and set aside.&lt;/li&gt;
&lt;li&gt;While the beef is cooking, steam the broccoli until it's almost (but not
   quite) cooked through. I typically do this by putting it in a large bowl,
   adding 2 tbsp water, covering it and microwaving: 3 minutes on high if
   frozen, 1&amp;frac12; minutes on high if fresh, pausing halfway through to stir.&lt;/li&gt;
&lt;li&gt;Once all the beef is cooked and set aside, spray the pan or add oil to coat
   and add the garlic and black bean (if using). Stir and cook for 30-60
   seconds until fragrant.&lt;/li&gt;
&lt;li&gt;When the garlic is ready, give the sauce a quick stir and add it to the pan,
    using it to deglaze. Once there are no more bits stuck to the bottom and the
    sauce is thick to your liking, add the broccoli and beef to the pan. Mix
    until thoroughly coated in sauce and heated through. Taste and adjust
    seasoning (salt, pepper, soy, etc.) if necessary.&lt;/li&gt;
&lt;li&gt;Fluff the rice and serve. Enjoy!&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;But I am a vegetarian???&lt;/h3&gt;
&lt;p&gt;Seitan can substitute for the beef relatively easily. Finding a substitute for
oyster sauce is a little bit trickier, especially since it's the star
ingredient. You can buy vegetarian or vegan oyster sauce (they're usually
mushroom-based), but I have no idea how good they taste. You can also try
making it at home! If you do, let me know how it turns out?&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Repack Zoom .debs to remove the `ibus` dependency</title><link href="https://hashman.ca/zoom/" rel="alternate"></link><published>2020-04-09T00:00:00-04:00</published><updated>2020-04-09T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2020-04-09:/zoom/</id><summary type="html">&lt;p&gt;Zoom .deb files have a frustrating dependency on the ibus package. Let me show you how to remove it.&lt;/p&gt;</summary><content type="html">&lt;p&gt;For whatever reason, &lt;a href="https://zoom.us/"&gt;Zoom&lt;/a&gt; distributes .debs that have a
dependency on &lt;code&gt;ibus&lt;/code&gt;. &lt;code&gt;ibus&lt;/code&gt; is the "intelligent input bus" package and as far
as I'm aware, might be used for emoji input in chat or something?? But is
otherwise not actually a dependency of the Zoom package. I've tested this
extensively... the client works fine without it.&lt;/p&gt;
&lt;p&gt;I noticed when I installed &lt;code&gt;ibus&lt;/code&gt; along with the Zoom package that &lt;code&gt;ibus&lt;/code&gt; would
frequently eat an entire core of CPU. I'm sure this is a bug in the &lt;code&gt;ibus&lt;/code&gt;
package or service, but I have no energy to try to get that fixed.  If it's not
a hard dependency, Zoom &lt;em&gt;shouldn't depend on it in the first place.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Anyways, here's how you can repack a Zoom .deb to remove the &lt;code&gt;ibus&lt;/code&gt; dependency:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;scratch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="k"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Extract package contents&lt;/span&gt;
dpkg&lt;span class="w"&gt; &lt;/span&gt;-x&lt;span class="w"&gt; &lt;/span&gt;zoom_amd64.deb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$scratch&lt;/span&gt;

&lt;span class="c1"&gt;# Extract package control information&lt;/span&gt;
dpkg&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;zoom_amd64.deb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$scratch&lt;/span&gt;/DEBIAN

&lt;span class="c1"&gt;# Remove the ibus dependency&lt;/span&gt;
sed&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;-E&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/(ibus, |, ibus)//&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$scratch&lt;/span&gt;/DEBIAN/control

&lt;span class="c1"&gt;# Rebuild the .deb&lt;/span&gt;
dpkg&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$scratch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;patched_zoom_amd64.deb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you can install the patched .deb with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;dpkg&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;patched_zoom_amd64.deb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The upstream fix would be for Zoom to move the &lt;code&gt;ibus&lt;/code&gt; "Dependency" to a
"Recommends", but they have been unwilling to do this for over a year.&lt;/p&gt;
&lt;h3&gt;But wait, what version even is my package?&lt;/h3&gt;
&lt;p&gt;By the way, you may have &lt;em&gt;also&lt;/em&gt; noticed that the Zoom client downloads do not
conform to the standard Debian package naming scheme (i.e. including the
version in the filename). If you're not sure what version a &lt;code&gt;zoom_amd64.deb&lt;/code&gt;
package you've downloaded is, you can quickly extract that information with
&lt;code&gt;dpkg-deb&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;dpkg-deb&lt;span class="w"&gt; &lt;/span&gt;-I&lt;span class="w"&gt; &lt;/span&gt;zoom_amd64.deb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Version
&lt;span class="c1"&gt;# Version: 3.5.383291.0407&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="blog"></category></entry><entry><title>Chili</title><link href="https://hashman.ca/chili/" rel="alternate"></link><published>2020-03-02T19:00:00-05:00</published><updated>2020-03-02T19:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2020-03-02:/chili/</id><summary type="html">&lt;p&gt;This is my recipe for homemade chili.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I really like beans. This is one way for me to power through the copious
amounts I receive through the beloved &lt;a href="https://www.ranchogordo.com/collections/samplers-and-sets/products/the-rancho-gordo-bean-club"&gt;Bean of the Month Club&lt;/a&gt;. (It took
me many months, but I finally got in!)&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;&lt;p lang="en" dir="ltr"&gt;
Cooked beans two days in a row in order to deliver this masterpiece &lt;a
href="https://t.co/VzIlPKKosJ"&gt;pic.twitter.com/VzIlPKKosJ&lt;/a&gt;&lt;/p&gt;
&amp;mdash; e. hashman (@ehashdn) &lt;a href="https://twitter.com/ehashdn/status/1234669958426005505?ref_src=twsrc%5Etfw"&gt;March 3, 2020&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;h2&gt;Beef Chili&lt;/h2&gt;
&lt;p&gt;Serves 5-7. Active time: 20m. Total time: 90m.&lt;/p&gt;
&lt;p&gt;Ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1lb lean ground beef&lt;/li&gt;
&lt;li&gt;1 large onion&lt;/li&gt;
&lt;li&gt;1 poblano pepper (or use your favourite peppers)&lt;/li&gt;
&lt;li&gt;1 stick celery&lt;/li&gt;
&lt;li&gt;some fresh garlic (idk, 2-3 cloves?)&lt;/li&gt;
&lt;li&gt;2 tablespoons ancho chili powder&lt;/li&gt;
&lt;li&gt;3&amp;frac12; teaspoons ground cumin&lt;/li&gt;
&lt;li&gt;2 teaspoons oregano&lt;/li&gt;
&lt;li&gt;2 teaspoons garlic powder&lt;/li&gt;
&lt;li&gt;14oz can diced tomatoes&lt;/li&gt;
&lt;li&gt;14oz can crushed tomatoes&lt;/li&gt;
&lt;li&gt;3 cups big cooked beans (I love &lt;a href="https://www.ranchogordo.com/products/ayocote-morado"&gt;ayacote morado&lt;/a&gt; for this)&lt;/li&gt;
&lt;li&gt;3 cups small cooked beans (pinto work great)&lt;/li&gt;
&lt;li&gt;salt to taste&lt;/li&gt;
&lt;li&gt;wedge of lime (optional)&lt;/li&gt;
&lt;li&gt;garnishes (sour cream, grated cheese, green onion, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recipe:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Heat a dutch oven on high.&lt;/li&gt;
&lt;li&gt;Small or medium dice (depending on your preference) the celery, pepper, and
   onion. You should have about four cups total.&lt;/li&gt;
&lt;li&gt;Brown the beef in the dutch oven, using a little bit of cooking oil to avoid
   sticking if desired.&lt;/li&gt;
&lt;li&gt;While the meat is browning, mince the garlic, measure the spices, and
   combine these all together.&lt;/li&gt;
&lt;li&gt;Once the meat is brown, add the diced vegetables and cook until tender and
   the onion is translucent.&lt;/li&gt;
&lt;li&gt;Add the spices and garlic, thoroughly combine, and cook until fragrant,
   about one minute.&lt;/li&gt;
&lt;li&gt;Add the tomatoes. Once the mixture comes to a boil, cover and simmer for
   about an hour, stirring every ~20 minutes or so.&lt;/li&gt;
&lt;li&gt;Add the beans and use bean broth or water to adjust consistency.&lt;/li&gt;
&lt;li&gt;This is a good time to taste and add salt. I usually use 1 to 1&amp;frac12;
   teaspoons.&lt;/li&gt;
&lt;li&gt;Bring to a boil again, cover and simmer for 10-15 more minutes.&lt;/li&gt;
&lt;li&gt;Turn off the heat, taste, and adjust seasoning if necessary. Add a squeeze
    of lime if it needs a little acidity.&lt;/li&gt;
&lt;li&gt;Serve with sour cream, grated cheese, sliced green onions, or any of your
    other favourite garnishes. &lt;/li&gt;
&lt;li&gt;Enjoy!&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-conversation="none" data-lang="en" data-dnt="true"&gt;&lt;p lang="en" dir="ltr"&gt;
before and after &lt;a href="https://t.co/CgkeCDPOaO"&gt;pic.twitter.com/CgkeCDPOaO&lt;/a&gt;&lt;/p&gt;&amp;mdash; e. hashman (@ehashdn) &lt;a href="https://twitter.com/ehashdn/status/1234671272870629377?ref_src=twsrc%5Etfw"&gt;March 3, 2020&lt;/a&gt;&lt;/blockquote&gt;

&lt;h3&gt;Frequently Asked Questions&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; &lt;em&gt;Why wait until basically the end to add salt?&lt;/em&gt;
&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Because canned ingredients will contain salt, and it's hard to predict
how much, so you should always salt to taste. Waiting until the end will always
ensure you season accurately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; &lt;em&gt;Why are so many of these directions so hand-wavey?&lt;/em&gt;
&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Cooking is an adventure. Experiment a little!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; &lt;em&gt;But I have no idea what "to taste" means.&lt;/em&gt;
&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; Taste it, add the thing, stir, taste it again. Is it salty enough? Sour
enough? Sweet enough? You don't know, you say? Keep going. Add a little too
much and then you'll find out for next time. &amp;#x1F601;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; &lt;em&gt;Why do you add so many beans and so little meat?&lt;/em&gt;
&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt; I really like beans.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>KubeCon NA 2019 Talk Resources</title><link href="https://hashman.ca/kubecon-2019/" rel="alternate"></link><published>2020-01-04T00:00:00-05:00</published><updated>2020-01-04T00:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2020-01-04:/kubecon-2019/</id><summary type="html">&lt;p&gt;Talk resources for "Weighing a Cloud: Measuring Your Kubernetes Clusters", copresented at KubeCon NA 2019 with Han Kang.&lt;/p&gt;</summary><content type="html">&lt;p&gt;At &lt;a href="https://kccncna19.sched.com/event/UaeP"&gt;KubeCon + CloudNativeCon North America 2019&lt;/a&gt;, I co-presented
"Weighing a Cloud: Measuring Your Kubernetes Clusters" with &lt;a href="https://github.com/logicalhan"&gt;Han Kang&lt;/a&gt;.
Here's some links and resources related to my talk, for your reference.&lt;/p&gt;
&lt;h2&gt;Weighing a Cloud: Measuring Your Kubernetes Clusters&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://static.sched.com/hosted_files/kccncna19/95/Weighing%20a%20Cloud%3A%20Measuring%20Your%20Kubernetes%20Clusters.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=BknenxQ_NLQ"&gt;Talk video, hosted on YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/srecon-2019"&gt;Related talk from SREcon:&lt;/a&gt; Kubernetes SLOs and debugging
  cluster issues&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ehashman/k8s-monitoring-demo"&gt;Try it yourself: sample code on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://prometheus.io/docs/introduction/overview"&gt;Prometheus documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;iframe style="display: block; margin: auto;" width="560" height="315" src="https://www.youtube-nocookie.com/embed/BknenxQ_NLQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h3&gt;Related readings&lt;/h3&gt;
&lt;p&gt;I'm including these documents for reference to add some context around what's
currently happening (as of 2019Q4) in the Kubernetes instrumentation SIG and
wider ecosystem.&lt;/p&gt;
&lt;p&gt;Note that GitHub links are pinned to their most recent commit to ensure they will not break; if you want the latest version, make sure to switch the branch to "master".&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/document/d/17emKiwJeqfrCsv0NZ2FtyDbenXGtTNCsDEiLbPa7x7Y/edit"&gt;SIG Instrumentation Meeting Minutes&lt;/a&gt; (note: you must join the &lt;a href="https://groups.google.com/forum/#!forum/kubernetes-sig-instrumentation"&gt;Google
  Group&lt;/a&gt; to be able to access these)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/enhancements/blob/f6af521711a28222726d8e5027c54ceceb02a417/keps/sig-instrumentation/20181106-kubernetes-metrics-overhaul.md"&gt;Kubernetes 1.14 metrics overhaul&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/enhancements/blob/f6af521711a28222726d8e5027c54ceceb02a417/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md"&gt;Metrics Stability Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/enhancements/blob/f6af521711a28222726d8e5027c54ceceb02a417/keps/sig-instrumentation/20190605-metrics-stability-migration.md"&gt;Metrics Stability Migration Plan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/community/blob/3547a212cc56c04657763b96759e51109c5c79a0/contributors/design-proposals/instrumentation/monitoring_architecture.md"&gt;Kubernetes monitoring architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/community/blob/3547a212cc56c04657763b96759e51109c5c79a0/contributors/devel/sig-instrumentation/instrumentation.md"&gt;Kubernetes instrumentation guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="talks"></category></entry><entry><title>My favourite bash alias for git</title><link href="https://hashman.ca/git-bash-alias/" rel="alternate"></link><published>2019-08-03T00:00:00-04:00</published><updated>2019-08-03T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2019-08-03:/git-bash-alias/</id><summary type="html">&lt;p&gt;Here's a non-trivial bash alias that I use in my day-to-day git workflow you might find handy.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I review a lot of code. &lt;a href="https://github.com/ehashman#user-activity-overview"&gt;&lt;em&gt;A lot.&lt;/em&gt;&lt;/a&gt; And an important part of that
process is getting to experiment with said code so I can make sure it actually
works. As such, I find myself with a frequent need to locally run code from a
submitted patch.&lt;/p&gt;
&lt;p&gt;So how does one fetch that code? Long ago, when I was a new maintainer, I would
add the remote repository I was reviewing to my local repo so I could fetch
that whole fork and target branch. Once downloaded, I could play around with
that on my local machine. But this was a lot of overhead! There was a lot of
clicking, copying, and pasting involved in order to figure out the clone URL
for the remote repo, and a bunch of commands to set it up. It felt like a lot
of toil that could be easily automated, but I didn't know a better way.&lt;/p&gt;
&lt;p&gt;One day, when &lt;a href="https://langui.sh/"&gt;a coworker of mine&lt;/a&gt; saw me struggling with this, he showed
me the better way.&lt;/p&gt;
&lt;p&gt;Turns out, most hosted git repos with pull request functionality will let you
pull down a read-only version of the changeset from the upstream fork using
git, meaning that you &lt;em&gt;don't&lt;/em&gt; have to set up additional remote tracking to
fetch and run the patch or use platform-specific HTTP APIs.&lt;/p&gt;
&lt;h2&gt;Using GitHub's git references for pull requests&lt;/h2&gt;
&lt;p&gt;I first learned how to do this on GitHub.&lt;/p&gt;
&lt;p&gt;GitHub maintains a copy of pull requests against a particular repo at the
&lt;a href="https://help.github.com/en/articles/checking-out-pull-requests-locally#modifying-an-inactive-pull-request-locally"&gt;&lt;code&gt;pull/NUM/head&lt;/code&gt; reference&lt;/a&gt;. (More documentation on refs &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Git-References"&gt;here&lt;/a&gt;.)
This means that if you have set up a remote called &lt;code&gt;origin&lt;/code&gt; and someone submits
a pull request #123 against that repository, you can fetch the code by running&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ git fetch origin pull/123/head
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 4 (delta 3), reused 3 (delta 3), pack-reused 1
Unpacking objects: 100% (4/4), done.
From github.com:ehashman/hack_the_planet
 * branch            refs/pull/123/head -&amp;gt; FETCH_HEAD

$ git checkout FETCH_HEAD
Note: checking out &amp;#39;FETCH_HEAD&amp;#39;.

You are in &amp;#39;detached HEAD&amp;#39; state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b &amp;lt;new-branch-name&amp;gt;

HEAD is now at deadb00 hack the planet!!!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Woah.&lt;/p&gt;
&lt;h3&gt;Using pull request references for CI&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;As a quick aside:&lt;/strong&gt; This is also handy if you want to write your own CI
scripts against users' pull requests. Even better&amp;mdash;on GitHub, you can
fetch a tree with the pull request &lt;em&gt;already merged&lt;/em&gt; onto the top of the current
master branch by fetching &lt;code&gt;pull/NUM/merge&lt;/code&gt;. (I'm not sure if this is officially
documented somewhere, and I don't believe it's widely supported by other hosted
git platforms.)&lt;/p&gt;
&lt;p&gt;If you also specify the &lt;code&gt;--depth&lt;/code&gt; flag in your fetch command, you can fetch
code even faster by limiting how much upstream history you download. It doesn't
make much difference on small repos, but it is a big deal on large projects:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;elana&lt;/span&gt;&lt;span class="nv"&gt;@silverpine&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;span class="n"&gt;Cloning&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kubernetes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nl"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Enumerating&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;295&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nl"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;295&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;295&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nl"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Compressing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;167&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;167&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nl"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;980446&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;148&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reused&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;136&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;reused&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;980151&lt;/span&gt;
&lt;span class="n"&gt;Receiving&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;980446&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;980446&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;648.95&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.47&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;Resolving&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;686795&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;686795&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;Checking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20279&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;20279&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;real&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;m31&lt;/span&gt;&lt;span class="mf"&gt;.035&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;m17&lt;/span&gt;&lt;span class="mf"&gt;.856&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m7&lt;/span&gt;&lt;span class="mf"&gt;.782&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="n"&gt;elana&lt;/span&gt;&lt;span class="nv"&gt;@silverpine&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;shallow&lt;/span&gt;
&lt;span class="n"&gt;Cloning&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kubernetes-shallow&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nl"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Enumerating&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;34305&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nl"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;34305&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;34305&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nl"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Compressing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;22976&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;22976&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nl"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;34305&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17247&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reused&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19060&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10567&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pack&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;reused&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;Receiving&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;34305&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;34305&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;34.22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;10.25&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;Resolving&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;deltas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17247&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;17247&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;real&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m31&lt;/span&gt;&lt;span class="mf"&gt;.495&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m3&lt;/span&gt;&lt;span class="mf"&gt;.941&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="mf"&gt;.228&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Writing the &lt;code&gt;pull&lt;/code&gt; alias&lt;/h2&gt;
&lt;p&gt;So how can one harness all this as a bash alias? It takes just a little bit of
code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pull&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;fetch&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pull/&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;/head&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;FETCH_HEAD
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pull&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pull&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then I can check out a PR locally with the short command &lt;code&gt;pull &amp;lt;remote&amp;gt; &amp;lt;num&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$ pull origin 123
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Total 5 (delta 4), reused 4 (delta 4), pack-reused 1
Unpacking objects: 100% (5/5), done.
From github.com:ehashman/hack_the_planet
 * branch            refs/pull/123/head -&amp;gt; FETCH_HEAD
Note: checking out &amp;#39;FETCH_HEAD&amp;#39;.

You are in &amp;#39;detached HEAD&amp;#39; state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b &amp;lt;new-branch-name&amp;gt;

HEAD is now at deadb00 hack the planet!!!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can even add your own commits, save them on a local branch, and push that
to your collaborator's repository to build on their PR if you're so inclined...
but let's not get too ahead of ourselves.&lt;/p&gt;
&lt;h2&gt;Changeset references on other git platforms&lt;/h2&gt;
&lt;p&gt;These pull request refs are not a special feature of git itself, but rather a
per-platform implementation detail using an arbitrary git ref format. As far as
I'm aware, most major git hosting platforms implement this, but they all use
slightly different ref names.&lt;/p&gt;
&lt;h3&gt;GitLab&lt;/h3&gt;
&lt;p&gt;At my last job I needed to figure out how to make this work with GitLab in
order to set up CI pipelines with our Jenkins instance. Debian's &lt;a href="https://salsa.debian.org/"&gt;Salsa&lt;/a&gt;
platform also runs GitLab.&lt;/p&gt;
&lt;p&gt;GitLab calls user-submitted changesets "merge requests" and that language is
reflected here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git fetch origin merge-requests/NUM/head
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;They also have some &lt;a href="https://gitlab.com/help/user/project/merge_requests/index.md#checkout-merge-requests-locally"&gt;nifty documentation&lt;/a&gt; for adding a git alias to
fetch these references. They do so in a way that creates a local branch
automatically, if that's something you'd like&amp;mdash;personally, I check out so
many patches that I would not be able to deal with cleaning up all the extra
branch mess!&lt;/p&gt;
&lt;h3&gt;BitBucket&lt;/h3&gt;
&lt;p&gt;Bad news: as of the time of publication, &lt;a href="https://bitbucket.org/site/master/issues/5814/reify-pull-requests-by-making-them-a-ref"&gt;this isn't supported on
bitbucket.org&lt;/a&gt;, even though a request for this feature has been open
for seven years. (BitBucket Server supports this feature, but that's standalone
and proprietary, so I won't bother including it in this post.)&lt;/p&gt;
&lt;h3&gt;Gitea&lt;/h3&gt;
&lt;p&gt;While I can't find any official documentation for it, I tested and confirmed
that Gitea uses the same ref names for pull requests as GitHub, and thus you
can use the same bash/git aliases on a Gitea repo as those you set up for
GitHub.&lt;/p&gt;
&lt;h2&gt;Saved you a click?&lt;/h2&gt;
&lt;p&gt;Hope you found this guide handy. No more excuses: now that it's just one short
command away, go forth and run your colleagues' code locally!&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>How to grant (Tom Marble) Debian Maintainer access</title><link href="https://hashman.ca/dm-access/" rel="alternate"></link><published>2019-07-24T00:00:00-04:00</published><updated>2019-07-24T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2019-07-24:/dm-access/</id><summary type="html">&lt;p&gt;I needed to give Tom Marble DM access to some team packages, but I keep forgetting how I did that previously, so I'll document it in this post.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I run the Debian Clojure Team, which means that occasionally folks volunteer to
help out with Clojure packaging. This is awesome! Since I'm lazy, I don't want
to have to sponsor every package upload for folks who have proven their
aptitude at packaging. Hence, sometimes I need to grant Debian Maintainers
upload access to team packages.&lt;/p&gt;
&lt;p&gt;Folks typically point at &lt;a href="https://lists.debian.org/debian-devel-announce/2012/09/msg00008.html"&gt;this email&lt;/a&gt; as documentation of how to grant
DM access on packages. However, I have zero desire to hand-craft artisanal
&lt;code&gt;dak&lt;/code&gt; commands. So, I try to leverage some existing tools I already have
installed on my system to help me out&amp;mdash;namely, the &lt;a href="https://manpages.debian.org/buster/dput-ng/dcut.1.en.html"&gt;&lt;code&gt;dcut&lt;/code&gt;&lt;/a&gt; tool
from the &lt;a href="https://packages.debian.org/buster/dput-ng"&gt;&lt;code&gt;dput-ng&lt;/code&gt; package&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The commands&lt;/h2&gt;
&lt;p&gt;Tom Marble wanted DM access to the &lt;a href="https://packages.debian.org/buster/libjava-jdbc-clojure"&gt;&lt;code&gt;libjava-jdbc-clojure&lt;/code&gt; package&lt;/a&gt;,
after I suggested he try doing a new version upload for it. I previously gave
him DM access to maintain &lt;code&gt;shimdandy&lt;/code&gt; and &lt;code&gt;com-hypirion-io-clojure&lt;/code&gt;. But I
couldn't remember exactly how I did it...&lt;/p&gt;
&lt;p&gt;According to the &lt;code&gt;dcut&lt;/code&gt; manpage, this should be as simple as running&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;dcut&lt;span class="w"&gt; &lt;/span&gt;dm&lt;span class="w"&gt; &lt;/span&gt;--uid&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Tom Marble&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--allow&lt;span class="w"&gt; &lt;/span&gt;libjava-jdbc-clojure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, there is a slight problem: I don't normally run &lt;code&gt;dput&lt;/code&gt; (or &lt;code&gt;dcut&lt;/code&gt;) on
a machine with my Debian key present, since I keep my only copy on my laptop.
For various reasons (mostly related to intertia, external monitors, and wifi
drivers), I run Linux Mint on my laptop, and the version of &lt;code&gt;dcut&lt;/code&gt; available
there doesn't actually work properly, so I can't just run &lt;code&gt;dcut&lt;/code&gt; locally...&lt;/p&gt;
&lt;p&gt;What to do about this?&lt;/p&gt;
&lt;p&gt;It turns out that there is an &lt;em&gt;undocumented&lt;/em&gt; flag, &lt;code&gt;-S&lt;/code&gt; or &lt;code&gt;--save&lt;/code&gt;, that will
save the generated commands locally.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;dcut&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;dm&lt;span class="w"&gt; &lt;/span&gt;--uid&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Tom Marble&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--allow&lt;span class="w"&gt; &lt;/span&gt;libjava-jdbc-clojure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-s&lt;/code&gt; flag, or &lt;code&gt;--simulate&lt;/code&gt;, ensures that we don't try to upload the file to
the archive just yet. This will produce a file in the current directory with a
name similar to &lt;code&gt;ehashman-1564016122.dak-commands&lt;/code&gt;. Take a look:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ehashman@corn-syrup:~$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;ehashman-1564016122.dak-commands

Archive:&lt;span class="w"&gt; &lt;/span&gt;ftp.upload.debian.org
Uploader:&lt;span class="w"&gt; &lt;/span&gt;Elana&lt;span class="w"&gt; &lt;/span&gt;Hashman&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ehashman@debian.org&amp;gt;

Action:&lt;span class="w"&gt; &lt;/span&gt;dm
Fingerprint:&lt;span class="w"&gt; &lt;/span&gt;884A52C4AC8ABB931D158FA840BFEE868B055D9A
Allow:&lt;span class="w"&gt; &lt;/span&gt;libjava-jdbc-clojure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now is a good time to verify that the key and package is correct. You can then
sign this file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gpg&lt;span class="w"&gt; &lt;/span&gt;--sign&lt;span class="w"&gt; &lt;/span&gt;--armour&lt;span class="w"&gt; &lt;/span&gt;--clearsign&lt;span class="w"&gt; &lt;/span&gt;ehashman-1564016122.dak-commands
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And use &lt;code&gt;dcut&lt;/code&gt; to upload it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;dcut&lt;span class="w"&gt; &lt;/span&gt;upload&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;ehashman-1564016122.dak-commands
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the file has been processed, check the &lt;a href="https://ftp-master.debian.org/dm.txt"&gt;FTP Master DM log&lt;/a&gt; to make
sure your DM changes have been set correctly.&lt;/p&gt;
&lt;p&gt;See you on the next episode of "me creating problems for myself with scary
Debian tools" &amp;#x1F44B;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dput-ng&lt;/code&gt; &lt;a href="http://dput-ng.debian.net"&gt;documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dcut&lt;/code&gt; &lt;a href="https://manpages.debian.org/buster/dput-ng/dcut.1.en.html"&gt;manpage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ftp-master.debian.org/dm.txt"&gt;Current DM permissions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category></entry><entry><title>PyCon 2019 Talk Resources</title><link href="https://hashman.ca/pycon-2019/" rel="alternate"></link><published>2019-05-01T00:00:00-04:00</published><updated>2019-05-01T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2019-05-01:/pycon-2019/</id><summary type="html">&lt;p&gt;Talk resources for "The Black Magic of Python Wheels", presented at PyCon US 2019.&lt;/p&gt;</summary><content type="html">&lt;p&gt;At PyCon US in 2019, I reprised my talk "The Black Magic of Python Wheels",
originally presented at &lt;a href="/pygotham-2018"&gt;PyGotham 2018&lt;/a&gt;. I based this talk on
my three years of work on &lt;a href="https://github.com/pypa/auditwheel/"&gt;&lt;code&gt;auditwheel&lt;/code&gt;&lt;/a&gt; and the &lt;a href="https://github.com/pypa/manylinux"&gt;&lt;code&gt;manylinux&lt;/code&gt;
platform&lt;/a&gt;, hoping to share some dark details of how the proverbial
sausage is made.&lt;/p&gt;
&lt;p&gt;After this talk, I will be &lt;a href="/leaving-pypa"&gt;retiring from &lt;code&gt;auditwheel&lt;/code&gt;
maintainership&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The Black Magic of Python Wheels&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://us.pycon.org/2019/schedule/presentation/186/"&gt;Talk page, PyCon website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=02aAZ8u3wEQ"&gt;Talk video, hosted on YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/pycon-2019/ehashman-pycon2019-slides.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pythonwheels.com"&gt;&lt;code&gt;pythonwheels.com&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pypa/python-manylinux-demo"&gt;Simple &lt;code&gt;manylinux&lt;/code&gt; wheelbuilding demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;iframe style="display: block; margin: auto;" width="560" height="315" src="https://www.youtube-nocookie.com/embed/02aAZ8u3wEQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h3&gt;Follow-up readings&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://man7.org/linux/man-pages/man5/elf.5.html"&gt;Linux Programmer's Manual: format of Executable and Linkable Format (ELF) Files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.man7.org/tlpi/"&gt;The Linux Programming Interface&lt;/a&gt;: 42.3.2 "Symbol Versioning", pg. 870. &lt;em&gt;(Note: all of
  chapter 42 would be a great resource on the topic! This is a great book.)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.akkadia.org/drepper/symbol-versioning"&gt;ELF Symbol Versioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://web.archive.org/web/20160107032111/http://www.trevorpounds.com/blog/?p=103"&gt;Linking to Older Versioned Symbols&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html"&gt;PLT and GOT - the key to code sharing and dynamic libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;All the PEPs referenced in the talk&lt;/h4&gt;
&lt;p&gt;In increasing numeric order.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0376/"&gt;PEP 376&lt;/a&gt; "Database of Installed Python Distributions"&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0426/"&gt;PEP 426&lt;/a&gt; "Metadata for Python Software Packages 2.0"&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0427/"&gt;PEP 427&lt;/a&gt; "The Wheel Binary Package Format 1.0"&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0513/"&gt;PEP 513&lt;/a&gt; "A Platform Tag for Portable Linux Built Distributions" (aka &lt;code&gt;manylinux1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0571/"&gt;PEP 571&lt;/a&gt; "The &lt;code&gt;manylinux2010&lt;/code&gt; Platform Tag"&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Image licensing info&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://plixs.com/photo/3297/tree-cat-silhouette-sunset"&gt;Tree Cat Silhouette Sunset&lt;/a&gt;: Public Domain (CC0) @besshamiti&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flic.kr/p/ArW1N9"&gt;Happy Halloween! (Costume Dog)&lt;/a&gt;: Public Domain (CC0) @milkyfactory&lt;/li&gt;
&lt;/ul&gt;</content><category term="talks"></category></entry><entry><title>I'm stepping down as maintainer of auditwheel</title><link href="https://hashman.ca/leaving-pypa/" rel="alternate"></link><published>2019-04-10T22:15:00-04:00</published><updated>2019-04-10T22:15:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2019-04-10:/leaving-pypa/</id><summary type="html">&lt;p&gt;After three years of work on auditwheel and the manylinux toolchain, I will be stepping away to focus on other open source projects.&lt;/p&gt;</summary><content type="html">&lt;p&gt;For the &lt;a href="https://github.com/pypa/auditwheel/graphs/contributors?from=2016-04-01&amp;amp;type=c&amp;amp;to=2019-04-11"&gt;last three years&lt;/a&gt; I've been a regular contributor and
core maintainer of &lt;a href="https://github.com/pypa/auditwheel"&gt;&lt;code&gt;auditwheel&lt;/code&gt;&lt;/a&gt;, a Python Packaging Authority (or
"PyPA") tool used to build portable binary/extension wheels on Linux.
&lt;code&gt;auditwheel&lt;/code&gt;'s "show" command allows developers to check if their Python
wheel's external symbol dependencies comply with the &lt;a href="https://www.python.org/dev/peps/pep-0513"&gt;manylinux&lt;/a&gt;
&lt;a href="https://www.python.org/dev/peps/pep-0571/"&gt;policies&lt;/a&gt;, and its "repair" command enables developers to more
easily build policy-compliant wheels inside an appropriate environment like a
&lt;a href="https://github.com/pypa/manylinux"&gt;manylinux Docker image&lt;/a&gt; without having to make significant changes
to their build processes.&lt;/p&gt;
&lt;p&gt;Most recently, at the last Python Packaging Authority sprints in November 2018,
I finished work to &lt;a href="https://github.com/pypa/auditwheel/pull/92"&gt;support the &lt;code&gt;manylinux2010&lt;/code&gt; platform tag in
&lt;code&gt;auditwheel&lt;/code&gt;&lt;/a&gt;.  After extensive testing, this functionality was
&lt;a href="https://github.com/pypa/auditwheel/releases"&gt;released&lt;/a&gt; in &lt;a href="https://github.com/pypa/auditwheel/releases/tag/2.0"&gt;version 2.0&lt;/a&gt; in January of 2019.&lt;/p&gt;
&lt;h2&gt;But why?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;auditwheel&lt;/code&gt; is a very technically challenging tool to maintain. It requires
deep knowledge of dynamic linking, ELF binaries, and symbol versioning on the
Linux platform. While this is very exciting technical work, it's not the sort
of project that I can work on sustainably in my free time and off hours. I'm
currently the only active &lt;code&gt;auditwheel&lt;/code&gt; maintainer, and I don't feel like I can
give the project the attention it deserves on an ongoing basis, especially
given community interest in &lt;a href="https://discuss.python.org/t/the-next-manylinux-specification/1043"&gt;updating the manylinux
specification&lt;/a&gt; and &lt;a href="https://github.com/pypa/auditwheel/issues/144"&gt;supporting new platform
policies&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On the bright side, concluding my work with &lt;code&gt;auditwheel&lt;/code&gt; and manylinux will
allow me to dedicate more quality time to other FOSS projects I'm excited
about! In a personal capacity, I have just started a two year term as an
individual member of the &lt;a href="https://opensource.org/board"&gt;Open Source Initiative Board of Directors&lt;/a&gt;, and
I will continue my &lt;a href="https://qa.debian.org/developer.php?login=ehashman&amp;amp;comaint=yes"&gt;work in Debian&lt;/a&gt;. In a professional capacity, I
recently started a new job at Red Hat and I intend to significantly increase my
upstream Kubernetes and OpenShift contributions over the next year.&lt;/p&gt;
&lt;p&gt;I'm making this announcement now to avoid surprising anyone at PyCon, and I'd
love to spend my time at the conference working on a transition plan. I will be
giving &lt;a href="https://us.pycon.org/2019/schedule/presentation/186/"&gt;an introductory talk about &lt;code&gt;auditwheel&lt;/code&gt;&lt;/a&gt; and the manylinux
toolchain if you're interested in learning more about the space and want to get
involved! At PyCon, I hope I will have the opportunity to provide some outgoing
input on the future of &lt;code&gt;auditwheel&lt;/code&gt; and manylinux, especially after &lt;a href="https://github.com/pypa/manylinux/issues/179"&gt;the bumpy
rollout of &lt;code&gt;manylinux2010&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So long and thanks for all the fish &amp;#x1F41F;&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>SREcon19 Americas Talk Resources</title><link href="https://hashman.ca/srecon-2019/" rel="alternate"></link><published>2019-03-22T00:00:00-04:00</published><updated>2019-03-22T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2019-03-22:/srecon-2019/</id><summary type="html">&lt;p&gt;Talk resources for "Operating within Normal Parameters: Monitoring Kubernetes", presented at SREcon19 Americas.&lt;/p&gt;</summary><content type="html">&lt;p&gt;At &lt;a href="https://www.usenix.org/conference/srecon19americas/presentation/hashman"&gt;SREcon19 Americas&lt;/a&gt;, I gave a talk called "Operating within Normal
Parameters: Monitoring Kubernetes". I also reprised this talk at the &lt;a href="https://www.meetup.com/Cloud-Native-PDX/events/265784684/"&gt;Cloud
Native PDX meetup&lt;/a&gt; in October 2019 and the &lt;a href="https://www.meetup.com/Portland-DevOps-GroundUp/events/djhzznybchbkc/"&gt;Portland DevOps
meetup&lt;/a&gt; in May 2020. Here's some links and resources related to my
talk, for your reference.&lt;/p&gt;
&lt;h2&gt;Operating within Normal Parameters: Monitoring Kubernetes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/srecon-2019/srecon-2019-ehashman.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GDo-Ixy_i9k"&gt;Talk video, hosted on YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ehashman/srecon-2019"&gt;Try it yourself: sample code on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://prometheus.io/docs/introduction/overview"&gt;Prometheus documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/kube-state-metrics"&gt;&lt;code&gt;kube-state-metrics&lt;/code&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes-incubator/metrics-server"&gt;&lt;code&gt;metrics-server&lt;/code&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.grafana.org/"&gt;Grafana documentation&lt;/a&gt; (for dashboards and visualization)&lt;/li&gt;
&lt;/ul&gt;
&lt;iframe style="display: block; margin: auto;" width="560" height="315" src="https://www.youtube-nocookie.com/embed/GDo-Ixy_i9k" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h3&gt;Additional Prometheus metrics sources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/prometheus/node_exporter"&gt;&lt;code&gt;node_exporter&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/prometheus/blackbox_exporter"&gt;&lt;code&gt;blackbox_exporter&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Related readings&lt;/h3&gt;
&lt;p&gt;I'm including these documents for reference to add some context around what's
currently happening (as of 2019Q1) in the Kubernetes instrumentation SIG and
wider ecosystem.&lt;/p&gt;
&lt;p&gt;Note that GitHub links are pinned to their most recent commit to ensure they will not break; if you want the latest version, make sure to switch the branch to "master".&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/document/d/17emKiwJeqfrCsv0NZ2FtyDbenXGtTNCsDEiLbPa7x7Y/edit"&gt;SIG Instrumentation Meeting Minutes&lt;/a&gt; (note: you must join the &lt;a href="https://groups.google.com/forum/#!forum/kubernetes-sig-instrumentation"&gt;Google
  Group&lt;/a&gt; to be able to access these)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/enhancements/blob/aaa166020d6fbfc5a32354588c9170c6085dddfb/keps/sig-instrumentation/0031-kubernetes-metrics-overhaul.md"&gt;Kubernetes 1.14 metrics overhaul (KEP-0031)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/community/blob/4fb3de39b0afa844098e48a1c1f2b6fdd064e91e/contributors/design-proposals/instrumentation/core-metrics-pipeline.md"&gt;Core Metrics proposal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/enhancements/blob/aaa166020d6fbfc5a32354588c9170c6085dddfb/keps/sig-node/kubelet-resource-metrics-endpoint.md"&gt;Kubelet Resource Metrics (formerly "Core Metrics") Endpoint proposal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/community/blob/4fb3de39b0afa844098e48a1c1f2b6fdd064e91e/contributors/design-proposals/instrumentation/monitoring_architecture.md"&gt;Kubernetes monitoring architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes/community/blob/4fb3de39b0afa844098e48a1c1f2b6fdd064e91e/contributors/devel/sig-instrumentation/instrumentation.md"&gt;Kubernetes instrumentation guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="talks"></category></entry><entry><title>I'm running for the Open Source Initiative Board of Directors</title><link href="https://hashman.ca/osi/" rel="alternate"></link><published>2019-03-02T11:00:00-05:00</published><updated>2019-03-02T11:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2019-03-02:/osi/</id><summary type="html">&lt;p&gt;I'm running as an individual member for the Board of Directors of the Open Source Initiative. I hope you'll consider joining and lending me your vote!&lt;/p&gt;</summary><content type="html">&lt;p&gt;The &lt;a href="https://opensource.org/elections"&gt;2019 election&lt;/a&gt; for the Open Source Initiative Board of Directors
is upon us, and I'm running for a seat on the board as an Individual Member.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://opensource.org/"&gt;Open Source Initiative (OSI)&lt;/a&gt; is a &lt;del&gt;shadowy cabal&lt;/del&gt; global
non-profit organization that is primarily responsible for maintaining the &lt;a href="https://opensource.org/osd-annotated"&gt;Open
Source Definition&lt;/a&gt; and &lt;a href="https://opensource.org/licenses/alphabetical"&gt;list of approved Open Source Licenses&lt;/a&gt;,
in addition to promoting and representing the wider open source community. If
you use or care about open source software, the OSI impacts you!&lt;/p&gt;
&lt;h2&gt;Why am I running?&lt;/h2&gt;
&lt;p&gt;There are three main things that I'd like to accomplish as a board member:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Grow the OSI's membership, and build a more representative organization.&lt;/li&gt;
&lt;li&gt;Defend the Open Source Definition and FOSS commons.&lt;/li&gt;
&lt;li&gt;Define the future of open source, as part of the larger community.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can read more of the specifics of &lt;a href="https://wiki.opensource.org/bin/Main/OSI+Board+of+Directors/Board+Member+Elections/Hashman2019"&gt;my platform&lt;/a&gt; on the OSI
election wiki.&lt;/p&gt;
&lt;h2&gt;Why vote for me?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;My platform is actionable, specific, and measurable.&lt;/strong&gt; For example, when I
say I want to grow the OSI's membership, this isn't just a platitude: I'm
running a membership drive to recruit 25 new members and I've nearly met my
goal already! If you vote for me, it's easy for you to hold me accountable to
these specific commitments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I have a cross-cutting, boots-on-the-ground view of the challenges and needs
of the FOSS community.&lt;/strong&gt; I'm active as a developer in many different open
source communities: the Python community, the Clojure community, the JavaScript
community, the Kubernetes and CNCF communities. I bring a new, broad
perspective to the Board as a primarily technical contributor from communities
who are not yet deeply involved with the OSI, and pledge to represent their
interests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;As a packager, I have a practical understanding of software licensing and
redistribution.&lt;/strong&gt; Defending the Open Source Definition isn't just about
ideology for me: threats to the FOSS commons directly impact my work as a
downstream developer. Packaging FOSS for distribution in Debian, applying
patches, and sharing derivative works all require a deep understanding of the
practice of software licenses and copyright. Hence, I have important and
applicable experience for &lt;a href="https://opensource.org/approval"&gt;license review&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;This sounds great, sign me up!&lt;/h2&gt;
&lt;p&gt;If you like what you've seen here, I'd be thrilled if you considered &lt;a href="https://opensource.org/members/join"&gt;joining
the OSI as a new member&lt;/a&gt; and voting for me.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://opensource.org/members/join"&gt;&lt;strong&gt;You can sign up for a membership here.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Do let me know if I was your inspiration for joining, as I'd love to count you
towards my membership drive! You can reach out via &lt;a href="https://toot.cat/@ehashman"&gt;Mastodon&lt;/a&gt;,
&lt;a href="https://twitter.com/ehashdn"&gt;Twitter&lt;/a&gt;, or &lt;a href="mailto:osi-2019-election@hashman.ca"&gt;email&lt;/a&gt;.  I'll also
make sure to send you a reminder to vote in the election. Voting opens Monday,
March 4 at 12:00am PST and closes Friday, March 15 at 11:59PM PST.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>get that (multigrain) bread 🍞</title><link href="https://hashman.ca/multigrain-bread/" rel="alternate"></link><published>2019-02-23T17:15:00-05:00</published><updated>2019-02-23T17:15:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2019-02-23:/multigrain-bread/</id><summary type="html">&lt;p&gt;Some ramblings about my adventures in breadmaking, and a recipe for my most successful multigrain loaf.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I've been baking a lot of bread over the past year: about one loaf a week, give
or take. It's a fun hobby, and it saves me a bit of money because homemade
bread lasts longer than the stuff at the grocery store and also costs less.
There are some occupational hazards, like burning my arm, but the payoff seems
to be mostly worth it, because homemade bread tastes &lt;em&gt;so good&lt;/em&gt;. The thing that
got me hooked was this &lt;a href="https://www.seriouseats.com/recipes/2010/05/bread-baking-the-simplest-white-bread-recipe-ever.html"&gt;basic recipe&lt;/a&gt; from Donna
Currie&amp;mdash;something about the overnight rest and use of good olive oil make
this loaf really magical, and the active time is minimal which made it easy for
me to get into baking regularly!&lt;/p&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;My beautiful golden son :&amp;#39;)
  &lt;a href="https://t.co/dNnwd0j8ZH"&gt;pic.twitter.com/dNnwd0j8ZH&lt;/a&gt;
 &lt;/p&gt;&amp;mdash; (:e hashman) (@ehashdn)
 &lt;a href="https://twitter.com/ehashdn/status/1081640710909165568?ref_src=twsrc%5Etfw"&gt;January 5, 2019&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;A thing I really appreciate about baking bread is that it's very forgiving.
I've only once ever made a loaf so bad that it turned out inedible, and that
was one among dozens. My bread-shaping technique was non-existent when I
started making bread, but now it's a lot better. I like making loaves on the
smaller side, but my loaf pans are the wrong size, so sometimes I end up with a
short, stout loaf&amp;mdash;who cares. Every week I get the opportunity to try a
new experiment and see what works and what doesn't, and my technique and
knowledge get better every time. Your loaves will not judge you. You do not
have to be perfect.&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;Compare this guy to the first loaf I baked when I got into
  bread earlier this year :D
  &lt;br&gt;&lt;br&gt;As they say, practice makes perfect.
  &lt;a href="https://t.co/nbF8l1e5UH"&gt;pic.twitter.com/nbF8l1e5UH&lt;/a&gt;
 &lt;/p&gt;&amp;mdash; (:e hashman) (@ehashdn)
 &lt;a href="https://twitter.com/ehashdn/status/1081651351724191744?ref_src=twsrc%5Etfw"&gt;January 5, 2019&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since I am Serious about breadmaking&amp;mdash;or, at least, relatively committed
to the cause&amp;mdash;I decided to make my own sourdough starter in December of
last year.  His name is &lt;strong&gt;Yeästeroth, Keeper of the Seal, Sourer of the Dough:
Yeästeroth the Undying, Who has Slept a Thousand Years... and Rises Again&lt;/strong&gt;.
(Name courtesy of my roommate. Other names submitted for consideration include
"Allison the Mermaid" and "libsour.so.5".)&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;7 days of Yeästeroth! To celebrate, my roommate started playing a chant from Mozart&amp;#39;s Requiem.
  &lt;br&gt;&lt;br&gt;
  Still moving along slower than I would like so I have swaddled him in a blanket.
  &lt;a href="https://t.co/CceLXjz1Xy"&gt;pic.twitter.com/CceLXjz1Xy&lt;/a&gt;
 &lt;/p&gt;&amp;mdash; (:e hashman) (@ehashdn)
 &lt;a href="https://twitter.com/ehashdn/status/1071051104945872897?ref_src=twsrc%5Etfw"&gt;December 7, 2018&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;According to various experiments, Yeästeroth sort of sucks at making dough rise
and I am not nearly patient enough to try to fix this. So I just appreciate his
nice flavour and spare him a little help in the rising department. When I bake
sourdough bread, I throw in an extra teaspoon of instant yeast and call it a day.&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;So it turns out that little bit of commercial yeast I was adding *was* doing something 😂 I have learned my lesson this week...
  &lt;br&gt;&lt;br&gt;
  Still tastes great, dense but good texture!
  &lt;a href="https://t.co/O52jf8R9I0"&gt;pic.twitter.com/O52jf8R9I0&lt;/a&gt;
 &lt;/p&gt;&amp;mdash; (:e hashman) (@ehashdn)
 &lt;a href="https://twitter.com/ehashdn/status/1084218708988448769?ref_src=twsrc%5Etfw"&gt;January 12, 2019&lt;/a&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Whole wheat: the final frontier&lt;/h2&gt;
&lt;p&gt;While getting started with white bread and sourdough was relatively easy,
baking with whole wheat flour is... a challenge, to say the least. It's much
less forgiving than baking with white flour, the doughs need much more
hydration so they're sticky and make a mess, and they rise at a different rate
than white bread.&lt;/p&gt;
&lt;p&gt;My favourite whole wheat breads tend to be multigrain, so that was the first
kind of whole wheat loaf I tried to bake. I wasn't super happy with it,
although I did bake &lt;a href="https://www.allrecipes.com/recipe/17780/hearty-multigrain-bread/"&gt;the recipe&lt;/a&gt; again to try to improve on my
technique, and that one turned out a bit better.&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;CRUMB
  &lt;a href="https://t.co/8LZNO7q2M5"&gt;pic.twitter.com/8LZNO7q2M5&lt;/a&gt;
 &lt;/p&gt;&amp;mdash; (:e hashman) (@ehashdn)
 &lt;a href="https://twitter.com/ehashdn/status/1023755927990755328?ref_src=twsrc%5Etfw"&gt;July 30, 2018&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be honest I didn't think that getting better at baking whole wheat bread was
actually worth the effort, so I stopped doing it for a while. Whole wheat bread
is not morally superior to white bread, and it's way harder to work with and
make taste good, so why bother with all the trouble?&lt;/p&gt;
&lt;p&gt;Well, one of my coworkers went to the UK over the winter break and brought
me back a bag of flour from his mother's local mill, and it turned out to be a
whole wheat seed mix flour for multigrain bread, so I felt &lt;em&gt;compelled&lt;/em&gt; to get
better at this. Look at how charming it is! The label uses Comic Sans!!&lt;/p&gt;
&lt;div style="text-align: center"&gt;
  &lt;img alt="Wessex Mill Six Seed Bread Flour (a photo of the flour packaging)"
       src="/multigrain-bread/sixseed.jpg" /&gt;
&lt;/div&gt;

&lt;p&gt;Since this flour has seeds already mixed in, a new and exciting thing for me, I
looked for a bread recipe &lt;a href="https://whatbread.wordpress.com/2013/02/24/wessex-mill-six-seed-bread-flour/"&gt;using it specifically&lt;/a&gt; (which was
really just &lt;a href="https://www.theguardian.com/lifeandstyle/wordofmouth/2010/jun/10/how-to-bake-wholemeal-bread"&gt;this recipe&lt;/a&gt;, modified) and made some modifications
of my own (sourdough starter/instant yeast mix, no vitamin C tablet, half the
salt, less sugar and used olive oil in place of butter). That turned out pretty
well.&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;Baked my best multigrain loaf yet today! With the flour
my coworker gave me 😊 &lt;a href="https://t.co/G4EYApU8zR"&gt;pic.twitter.com/G4EYApU8zR&lt;/a&gt;
 &lt;/p&gt;&amp;mdash; (:e hashman) (@ehashdn)
 &lt;a href="https://twitter.com/ehashdn/status/1091186059667484673?ref_src=twsrc%5Etfw"&gt;February 1, 2019&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;While I baked a pretty decent first loaf with the Wessex Mill flour, it still
felt like it lacked something. I missed the butter and the brown sugar and so
this time I figured I'd be a little more decadent and go all out. But I didn't
really trust myself to do that with a 100% whole wheat loaf and succeed, so I
decided to try an experiment by using a little more white flour. This new
recipe is a hybridization of all the various multigrain loaf recipes I've tried
thus far, and it worked out better than I could have hoped for!&lt;/p&gt;
&lt;h2&gt;My most successful multigrain loaf yet&lt;/h2&gt;
&lt;p&gt;Ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8oz &lt;a href="https://www.wessexmill.co.uk/acatalog/Six-Seed-Bread-Flour-1.5kg-X053S.html"&gt;Wessex Mill Six Seed Flour&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;4oz white bread flour (I use King Arthur brand)&lt;/li&gt;
&lt;li&gt;1 tsp instant yeast (I use Saf-instant red)&lt;/li&gt;
&lt;li&gt;1 tsp salt&lt;/li&gt;
&lt;li&gt;2 tbsp dark brown sugar&lt;/li&gt;
&lt;li&gt;8oz sourdough starter at 100% hydration, unfed&lt;/li&gt;
&lt;li&gt;6oz warm water&lt;/li&gt;
&lt;li&gt;1-2 tbsp melted butter (it's fine if it's salted)&lt;/li&gt;
&lt;li&gt;canola/vegetable oil for greasing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This recipe involves a rest in the fridge. I recommend mixing the
dough in the evening and baking it in the next morning.&lt;/p&gt;
&lt;p&gt;Recipe:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mix the dry ingredients in a stand mixer until thoroughly combined.&lt;/li&gt;
&lt;li&gt;Measure in the wet ingredients and mix in the stand mixer until they come
   together. At this point the dough will be an extremely sticky mess,
   completely attached to the sides of the bowl.&lt;/li&gt;
&lt;li&gt;Fear not. Add about a tablespoon of white bread flour and mix until it just
   starts to unstick from the sides of the mixer bowl.&lt;/li&gt;
&lt;li&gt;Grease a plastic bag with a bit of canola oil. Make sure you grease it
   really well, because otherwise the dough will stick to the bag and you will
   be sad. Scrape the dough out of the mixing bowl into the bag and seal it.
   Stick this in the fridge overnight so it can develop some nice flavour.&lt;/li&gt;
&lt;li&gt;In the morning, take the bag out of the fridge and let it come up to room
   temperature. This will take one to two hours, depending on how warm your
   kitchen is.&lt;/li&gt;
&lt;li&gt;When the dough is warmed up, sprinkle some flour on the counter and &lt;a href="https://www.youtube.com/watch?v=wx5I5O_RoeI"&gt;shape
   the dough into a log&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Grease a loaf pan and transfer the dough into the pan. Cover the pan with
   plastic wrap and let this rest in a warm place until the loaf is fully
   risen. I usually let mine go about an hour and a half to two hours,
   depending on how long it rested coming up to room temperature.
   &lt;br&gt;&lt;br&gt;
    &lt;img alt="Dough shaped into a log, beginning to rise in the loaf pan" src="/multigrain-bread/logrise.jpg"&gt;&lt;/li&gt;
&lt;li&gt;When the dough is just about ready (it should double in size, give or take),
   preheat the oven to 350F convection (or 375F conventional bake). Put the
   loaf in the oven and bake for 20 minutes.
   &lt;br&gt;&lt;br&gt;
    &lt;img alt="Fully risen loaf" src="/multigrain-bread/risenlog.jpg"&gt;&lt;/li&gt;
&lt;li&gt;At this point, turn the loaf around and lower the oven temperature to 325F
   convection (or 350F conventional bake). Bake for an additional 15 minutes.&lt;/li&gt;
&lt;li&gt;Remove the loaf from the oven, pop out of the pan and cool on a cooling
    rack. Enjoy once cool... assuming you can wait that long!
   &lt;br&gt;&lt;br&gt;
    &lt;img alt="Golden baked loaf, cooling on a cooling rack" src="/multigrain-bread/loaf.jpg"&gt;
    &lt;img alt="The loaf, sliced open" src="/multigrain-bread/crumb1.jpg"&gt;
    &lt;img alt="An irresistable slice of bread, revealing little bubbles and seeds" src="/multigrain-bread/crumb2.jpg"&gt;&lt;/li&gt;
&lt;/ol&gt;</content><category term="blog"></category></entry><entry><title>Hot chocolate</title><link href="https://hashman.ca/hot-chocolate/" rel="alternate"></link><published>2019-01-08T22:00:00-05:00</published><updated>2019-01-08T22:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2019-01-08:/hot-chocolate/</id><summary type="html">&lt;p&gt;Sharing some homemade hot chocolate recipes.&lt;/p&gt;</summary><content type="html">&lt;p&gt;My roommate once told me that &amp;ldquo;[I] make the best hot chocolate [he's]
ever tasted.&amp;rdquo; This was a little surprising to me, because my hot
chocolate recipe is not sophisticated, but I guess it &lt;em&gt;does&lt;/em&gt; taste pretty good.
&amp;#x1F60A;&lt;/p&gt;
&lt;p&gt;Today I will share my secrets with the world.&lt;/p&gt;
&lt;h2&gt;Homemade hot chocolate&lt;/h2&gt;
&lt;p&gt;Ingredients:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 tsp granulated sugar&lt;/li&gt;
&lt;li&gt;1 tbsp unsweetened cocoa powder&lt;/li&gt;
&lt;li&gt;splash of vanilla extract (or paste, if you're really fancy)&lt;/li&gt;
&lt;li&gt;hot water&lt;/li&gt;
&lt;li&gt;10-12oz milk (I like whole milk)&lt;/li&gt;
&lt;li&gt;pinch salt&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recipe:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mix the sugar, cocoa, and vanilla in a microwave-safe liquid measuring cup.
   Add a small amount of hot water and stir until the mixture is fully
   combined.&lt;/li&gt;
&lt;li&gt;Add milk while stirring until you have about one serving of hot chocolate,
   about 10-12oz. Taste.&lt;/li&gt;
&lt;li&gt;Adjust any ingredients to taste (more sugar, more cocoa, etc.) and add salt.&lt;/li&gt;
&lt;li&gt;Microwave for about 1 minute on high. Stir and taste for a temperature
   check.&lt;/li&gt;
&lt;li&gt;Microwave for about 30 more seconds or until sufficiently hot.&lt;/li&gt;
&lt;li&gt;Pour into a mug or thermos for serving.&lt;/li&gt;
&lt;li&gt;Enjoy!&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Variations&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Spicy hot chocolate:&lt;/strong&gt; substitute &amp;#188; tsp cinnamon for the vanilla. Add a
dash of cayenne.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Peppermint hot chocolate:&lt;/strong&gt; substitute a splash of mint extract for the
vanilla.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Non-dairy hot chocolate:&lt;/strong&gt; use your favourite non-dairy milk substitute in
place of milk. If it's vanilla-flavoured, leave out the vanilla. If it's
sweetened, you may need to reduce the amount of sugar added.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Software Freedom Conservancy: Governance &amp; Federation are the Future</title><link href="https://hashman.ca/conservancy-2018/" rel="alternate"></link><published>2018-12-27T12:00:00-05:00</published><updated>2018-12-27T12:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-12-27:/conservancy-2018/</id><summary type="html">&lt;p&gt;I spoke with Deb Nicholson from the Software Freedom Conservancy about federated free social media, project governance, and how I got my start in free software.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;This entry is cross-posted from the &lt;a href="https://sfconservancy.org/blog/2018/dec/27/elanahashman/"&gt;Software Freedom Conservancy's blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is part of our ongoing series on generous matching donors. Elana is the Queen of Debian Clojure, Empress of Symbol Versioning, Conqueress of ABIs, Python Packaging Authority, ELF Herder and the Winner of this year's Award for most odd, but needful volunteer assistance this year (keeping people from eating pizza on top of the Conservancy tablecloth and so, so much more.) Elana and several other outstanding individuals are joining Private Internet Access and a big anonymous donor in offering a total of &lt;a href="https://sfconservancy.org/news/2018/nov/20/90k-donation-match/"&gt;$90K in matching funds to the Conservancy&lt;/a&gt; for our continued work to provide both &lt;a href="https://sfconservancy.org/supporter/#growing-projects"&gt;support for important free software&lt;/a&gt; and a clear voice in favor of &lt;a href="https://sfconservancy.org/blog/2018/dec/11/compliance2/"&gt;community-driven licensing&lt;/a&gt; and governance practices. &lt;/p&gt;

&lt;div style="text-align: center"&gt;
  &lt;img style="max-height: 25em; max-width: 50%; width: auto;"
       alt="Elana hugging a plush cupcake toy."
       src="/images/cupcake.jpg" /&gt;
&lt;/div&gt;

&lt;p&gt;&lt;b&gt;Deb:&lt;/b&gt; What's the most exciting thing you've seen recently in free software? &lt;/p&gt;

&lt;p&gt;&lt;b&gt;EH:&lt;/b&gt; I'm really excited about a bunch of different emerging free social technologies based on the &lt;a 
href="https://activitypub.rocks/"&gt;ActivityPub&lt;/a&gt; specification that make up the so-called "fediverse." I think &lt;a href="https://joinmastodon.org/"&gt;Mastodon&lt;/a&gt; might be the most popular&amp;mdash;it fills a niche similar to Twitter&amp;mdash;but there's also &lt;a href="https://pleroma.social/"&gt;Pleroma&lt;/a&gt;, which is Mastodon-compatible and a little simpler to deploy, a peer-to-peer replacement for YouTube called &lt;a href="https://joinpeertube.org/en/"&gt;PeerTube&lt;/a&gt;, and a federated image sharing app you can use instead of Instagram called &lt;a href="https://pixelfed.org/"&gt;PixelFed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mastodon has demonstrated that when we prioritize user experiences and work together, we can build free software to sustainably run social collectives on independent infrastructure, and even achieve widespread adoption. This is so meaningful to me: the fediverse embodies all of user freedom, consent, autonomy, self-governance, and community in practice. Independent, federated social networks come with the promise of building online social spaces that better reflect the social needs of individuals and their communities in a way that centralized, corporate social media cannot.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Deb:&lt;/b&gt; What do you wish people knew about Conservancy, that they might not know? &lt;/p&gt;

&lt;p&gt;&lt;b&gt;EH:&lt;/b&gt; Many folks have heard of the wonderful projects that all live together under the Conservancy banner, but I'm not sure if many people are familiar with what it takes to become a Conservancy project!&lt;/p&gt;

&lt;p&gt;Conservancy members are required to serve the public interest, develop their software in public, and use a FOSS license. They must also be community-run: a Conservancy project should have a community-elected oversight committee or a minimum of three governing members, so a project can't be run by a single developer, and when members are appointed there can't be more than one employed by a particular company. I think it's really cool that all Conservancy member projects must uphold rigorous standards for community governance. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;Deb:&lt;/b&gt; You work on several well-known free software projects (Debian, Clojure, Python). Do you have any advice for folks who are just starting with free software contributing? &lt;/p&gt;

&lt;p&gt;&lt;b&gt;EH:&lt;/b&gt; It's funny when you put it that way---I got started in free software barely five years ago, and I'm almost surprised by how much I've contributed since then. One of the big barriers for me was believing I could do it at all. Even though I've been using free software since 2006 or so, I didn't really see a lot of people like me in the community, and having lurked in IRC channels for years I was so afraid of trying to 
contribute and getting yelled at for messing up something obvious.&lt;/p&gt;

&lt;p&gt;In 2013, I decided to attend an open source day at a conference, and met Asheesh Laroia and Carol Willing. They jumped to onboard me with OpenHatch, a project whose mission was to help newcomers get involved in free and open source software. That chance meeting grew into a GSoC internship with OpenHatch the next summer; later, I became a core maintainer of the project until it wound down. Once I had the right skills, it's become harder for me to say no to contributing to new projects than to just contribute! The fear of messing up spectacularly in public is still there, but it doesn't stop me anymore.&lt;/p&gt;

&lt;p&gt;Part of OpenHatch's legacy was encouraging projects to identify and publicly label issues that were relatively small (or "bite-sized") and good for beginners. Now, many spiritual successors to OpenHatch exist, including &lt;a href="https://yourfirstpr.github.io/"&gt;Your First PR&lt;/a&gt; and &lt;a href="https://up-for-grabs.net/"&gt;Up For Grabs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Deb:&lt;/b&gt; What do you hope to see Conservancy accomplish in the next five years? &lt;/p&gt;

&lt;p&gt;&lt;b&gt;EH:&lt;/b&gt; I think Conservancy is increasingly important for the future of sustainable free software. Recently, we've seen the proliferation of a &lt;a href="https://commonsclause.com/"&gt;number&lt;/a&gt; of &lt;a href="https://www.cockroachlabs.com/cockroachdb-community-license/"&gt;new&lt;/a&gt; &lt;a href="https://www.mongodb.com/licensing/server-side-public-license"&gt;protectionist&lt;/a&gt; &lt;a href="https://www.confluent.io/confluent-community-license"&gt;licenses&lt;/a&gt;, as corporations become more concerned about their open source projects being monetized by other corporations that don't contribute back. I think corporate sustainability and community sustainability are different things, and I'm concerned that the idea of "sustainability" is being co-opted by companies that define it as seeing greater financial 
returns from their open source projects.&lt;/p&gt;

&lt;p&gt;Conservancy fights this co-option with a two-pronged strategy: through its software license advocacy, by helping to educate the public on software licenses and by providing license enforcement to member projects to ensure free software remains free; and through its support of member project operations, by enabling the practice of sustainable community free software in providing fiscal sponsorship and administrative services. I think both are very important and I'd love to see Conservancy continue to grow in both areas over the next five years; perhaps it will even accept some fediverse projects as members :)&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Deb:&lt;/b&gt; Anything else you'd like to add? &lt;/p&gt;

&lt;p&gt;&lt;b&gt;EH:&lt;/b&gt; If any of this speaks to you, dear reader, then I'd love to encourage you to &lt;a href="https://sfconservancy.org/supporter/"&gt;support Conservancy by making a donation&lt;/a&gt;. But if that's not something you're able to do, you can always volunteer with Conservancy or a member project, or help &lt;a href="https://sfconservancy.org/supporter/banner/"&gt;spread the word&lt;/a&gt; for &lt;a href="https://sfconservancy.org/news/2018/nov/20/90k-donation-match/"&gt;this year's fundraiser!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Photo of Elana Hashman, courtesy of Elana Hashman, all rights reserved.&lt;/i&gt;&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>I was a podcast guest on The REPL</title><link href="https://hashman.ca/the-repl/" rel="alternate"></link><published>2018-10-26T16:00:00-04:00</published><updated>2018-10-26T16:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-10-26:/the-repl/</id><summary type="html">&lt;p&gt;Daniel Compton hosted me on his Clojure podcast, The REPL, where I talked about Debian, packaging Leiningen, and the Clojure ecosystem in Debian.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Daniel Compton &lt;a href="https://www.therepl.net/episodes/8/"&gt;hosted me on his Clojure podcast, The REPL&lt;/a&gt;, where I
talked about Debian, packaging Leiningen, and the Clojure ecosystem in Debian.
It's got everything: spooky abandoned packages, anarchist collectives, software
security policies, and Debian release cycles. Absolutely no shade was thrown at
other distros.&lt;/p&gt;
&lt;p&gt;Give it a listen:&lt;/p&gt;
&lt;div style="margin: auto; width: 40%"&gt;
  &lt;audio controls preload="none"&gt;
    Your browser does not support the &lt;code&gt;audio&lt;/code&gt; element.
    &lt;source src="https://media.therepl.net/therepl/therepl-008.mp3" type="audio/mpeg" /&gt;
  &lt;/audio&gt;
&lt;/div&gt;

&lt;p&gt;Download: &lt;a href="https://media.therepl.net/therepl/therepl-008.mp3"&gt;MP3&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;More Q&amp;amp;A&lt;/h2&gt;
&lt;p&gt;After the podcast was published, &lt;a href="http://softwaremaniacs.org/"&gt;Ivan Sagalaev&lt;/a&gt;
wrote me with a great question about how the different versions of Clojure in
Ubuntu 18.04 work:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;First of all, THANK YOU for making &lt;code&gt;sudo apt install leiningen&lt;/code&gt; work! It's so
much better and more consistent than sourcing bash scripts :-)&lt;/p&gt;
&lt;p&gt;I have a quick question for you. After installing &lt;code&gt;leiningen&lt;/code&gt; and &lt;code&gt;clojure&lt;/code&gt;
on Ubuntu 18.04 I see that &lt;code&gt;lein repl&lt;/code&gt; starts with clojure 1.8.0, while the
clojure package itself seems to be independent and is version 1.9.0. How is
it possible? I frankly haven't even seen &lt;code&gt;lein&lt;/code&gt; downloading its own
clojure.jar...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I replied:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Leiningen is "ahead-of-time (AOT) compiled", which is a fancy way of saying
that the Leiningen you download from Ubuntu is pre-built. This means it is
already compiled to Java bytecode, which can be run directly by Java. I ship
the binary Leiningen package as an &lt;a href="https://stackoverflow.com/questions/11947037/what-is-an-uber-jar"&gt;"uberjar"&lt;/a&gt;, which means all its
dependencies are also included inside the Leiningen jar.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://salsa.debian.org/clojure-team/leiningen-clojure/blob/2702c4ffd50ce4b691597ad351996e274491b430/leiningen-core/project.clj#L7"&gt;Leiningen depends on and is built with Clojure 1.8&lt;/a&gt;, so the
Leiningen uberjar in Debian also depends on Clojure 1.8. The &lt;a href="https://packages.ubuntu.com/bionic/clojure"&gt;"clojure"&lt;/a&gt;
package in 18.04 defaults to installing Clojure 1.9, but that can be
installed simultaneously with the &lt;a href="https://packages.ubuntu.com/bionic/clojure1.8"&gt;"clojure1.8"&lt;/a&gt; package that
Leiningen depends on in order to build. You can change your default Clojure
to 1.8 using
&lt;a href="https://manpages.debian.org/jessie/dpkg/update-alternatives.8.en.html"&gt;alternatives&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When you launch &lt;code&gt;lein repl&lt;/code&gt;, by default the Clojure 1.8 runtime that's
compiled in is used. If you run &lt;code&gt;lein repl&lt;/code&gt; in the root of a Clojure 1.9
project, Leiningen will download Clojure 1.9 from Clojars and launch a 1.9
repl. If you want to use the Clojure 1.9 shipped with Debian, &lt;a href="https://salsa.debian.org/clojure-team/leiningen-clojure/blob/master/debian/patches/0001-Build-in-offline-mode-with-local-repo.patch"&gt;you can change
&lt;code&gt;:local-repo&lt;/code&gt; to point at &lt;code&gt;/usr/share/maven-repo&lt;/code&gt;&lt;/a&gt;, but be careful to
also set &lt;code&gt;:offline?&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; so you don't try to install things into the
system maven repo by accident.&lt;/p&gt;
&lt;/blockquote&gt;</content><category term="blog"></category></entry><entry><title>PyGotham 2018 Talk Resources</title><link href="https://hashman.ca/pygotham-2018/" rel="alternate"></link><published>2018-10-13T00:00:00-04:00</published><updated>2018-10-13T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-10-13:/pygotham-2018/</id><summary type="html">&lt;p&gt;Talk resources for "The Black Magic of Python Wheels", presented at PyGotham 2018.&lt;/p&gt;</summary><content type="html">&lt;p&gt;At PyGotham in 2018, I gave a talk called "The Black Magic of Python Wheels". I
based this talk on my two years of work on &lt;a href="https://github.com/pypa/auditwheel/"&gt;&lt;code&gt;auditwheel&lt;/code&gt;&lt;/a&gt; and the
&lt;a href="https://github.com/pypa/manylinux"&gt;&lt;code&gt;manylinux&lt;/code&gt; platform&lt;/a&gt;, hoping to share some dark details of how the
proverbial sausage is made.&lt;/p&gt;
&lt;p&gt;It was a fun talk, and I enjoyed the opportunity to wear my Python Packaging
Authority hat:&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;A very witchy
  &lt;a href="https://twitter.com/PyGotham?ref_src=twsrc%5Etfw"&gt;@PyGotham&lt;/a&gt;
  talk from &lt;a href="https://twitter.com/ehashdn?ref_src=twsrc%5Etfw"&gt;@ehashdn&lt;/a&gt;
  about dark ELF magic
  &lt;a href="https://t.co/W8JMEVW8GE"&gt;pic.twitter.com/W8JMEVW8GE&lt;/a&gt;
 &lt;/p&gt;&amp;mdash; Geoffrey Thomas, but spooky (@geofft)
 &lt;a href="https://twitter.com/geofft/status/1048645263198474240?ref_src=twsrc%5Etfw"&gt;October 6, 2018&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;h2&gt;The Black Magic of Python Wheels&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://2018.pygotham.org/talks/understanding-the-black-magic-of-python-wheels/"&gt;Talk page, PyGotham website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/pygotham-2018/pygotham18-slides.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pythonwheels.com"&gt;&lt;code&gt;pythonwheels.com&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pypa/python-manylinux-demo"&gt;Simple &lt;code&gt;manylinux&lt;/code&gt; wheelbuilding demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Follow-up readings&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://man7.org/linux/man-pages/man5/elf.5.html"&gt;Linux Programmer's Manual: format of Executable and Linkable Format (ELF) Files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.man7.org/tlpi/"&gt;The Linux Programming Interface&lt;/a&gt;: 42.3.2 "Symbol Versioning", pg. 870. &lt;em&gt;(Note: all of
  chapter 42 would be a great resource on the topic! This is a great book.)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.akkadia.org/drepper/symbol-versioning"&gt;ELF Symbol Versioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://web.archive.org/web/20160107032111/http://www.trevorpounds.com/blog/?p=103"&gt;Linking to Older Versioned Symbols&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html"&gt;PLT and GOT - the key to code sharing and dynamic libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;All the PEPs referenced in the talk&lt;/h4&gt;
&lt;p&gt;In increasing numeric order.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0376/"&gt;PEP 376&lt;/a&gt; "Database of Installed Python Distributions"&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0426/"&gt;PEP 426&lt;/a&gt; "Metadata for Python Software Packages 2.0"&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0427/"&gt;PEP 427&lt;/a&gt; "The Wheel Binary Package Format 1.0"&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0513/"&gt;PEP 513&lt;/a&gt; "A Platform Tag for Portable Linux Built Distributions" (aka &lt;code&gt;manylinux1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.python.org/dev/peps/pep-0571/"&gt;PEP 571&lt;/a&gt; "The &lt;code&gt;manylinux2010&lt;/code&gt; Platform Tag"&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Image licensing info&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://plixs.com/photo/3297/tree-cat-silhouette-sunset"&gt;Tree Cat Silhouette Sunset&lt;/a&gt;: Public Domain (CC0) @besshamiti&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flic.kr/p/ArW1N9"&gt;Happy Halloween! (Costume Dog)&lt;/a&gt;: Public Domain (CC0) @milkyfactory&lt;/li&gt;
&lt;/ul&gt;</content><category term="talks"></category></entry><entry><title>Report on the Debian Bug Squashing Party</title><link href="https://hashman.ca/nyc-bsp-report/" rel="alternate"></link><published>2018-06-30T15:30:00-04:00</published><updated>2018-06-30T15:30:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-06-30:/nyc-bsp-report/</id><summary type="html">&lt;p&gt;The bug squashing party I held in Brooklyn, NY, USA for Debian was a smashing success! Here's what we accomplished.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last weekend, six folks (one new contributor and five existing contributors)
attended the bug squashing party I hosted in Brooklyn. We got a lot done, and
attendees demanded that we hold another one soon!&lt;/p&gt;
&lt;h2&gt;So when's the next one?&lt;/h2&gt;
&lt;p&gt;We agreed that we'd like to see the NYC Debian User Group hold two more BSPs in
the next year: one in October or November of 2018, and another after the Buster
freeze in early 2019, to squash RC bugs. Stay tuned for more details; you may
want to join the &lt;a href="https://lists.debian.org/debian-dug-nyc/"&gt;NYC Debian User Group mailing list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you know of an organization that would be willing to sponsor the next NYC
BSP (with space, food, and/or dollars), or you're willing to host the next BSP,
please &lt;a href="mailto:ehashman@debian.org?subject=Hosting%20the%20next%20NYC%20Debian%20BSP"&gt;reach out&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What did folks work on?&lt;/h2&gt;
&lt;p&gt;We had a list of bugs we collected on an &lt;a href="https://etherpad.net/p/bsp-nyc-0624"&gt;etherpad&lt;/a&gt;, which I have now
mirrored to gobby (&lt;code&gt;gobby.debian.org/BSP/2018/06-Brooklyn&lt;/code&gt;). Attendees updated
the etherpad with their comments and progress. Here's what each of the
participants reported.&lt;/p&gt;
&lt;h3&gt;Elana (me)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;I filed bugs against two upstream repos (&lt;a href="https://github.com/cemerick/pomegranate/issues/101"&gt;pomegranate&lt;/a&gt;,
  &lt;a href="https://github.com/technomancy/leiningen/issues/2443"&gt;leiningen&lt;/a&gt;) to update dependencies, which are breaking the Debian
  builds due to the &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=891175"&gt;libwagon upgrade&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I uploaded new versions of &lt;code&gt;clojure&lt;/code&gt; and &lt;code&gt;clojure1.8&lt;/code&gt; to fix a bug in how
  alternatives were managed: despite &lt;code&gt;/usr/share/java/clojure.jar&lt;/code&gt; being owned
  by the &lt;code&gt;libclojure${ver}-java&lt;/code&gt; binary package, the alternatives group was
  being managed by the postinst script in the &lt;code&gt;clojure${ver}&lt;/code&gt; package, a
  holdover from when the library was not split from the CLI. Unfortunately, the
  upgrade is still not passing piuparts in testing, so while I thoroughly
  tested local upgrades and they seemed to work okay I'm hoping &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=902445"&gt;the failures
  didn't break anyone on upgrade&lt;/a&gt;. I'll be taking a look at further
  refining the preinst script to address the piuparts failure this week.&lt;/li&gt;
&lt;li&gt;I fixed the Vcs error on &lt;code&gt;libjava-jdbc-clojure&lt;/code&gt; and uploaded new version
  0.7.0-2. I also added autopkgtests to the package.&lt;/li&gt;
&lt;li&gt;I fixed the Vcs warning on &lt;code&gt;clojure-maven-plugin&lt;/code&gt; and uploaded new version
  1.7.1-2.&lt;/li&gt;
&lt;li&gt;I helped dkg with setting up and running autopkgtests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href="https://xana.scru.org/"&gt;Clint&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;was hateful in
  &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=901327"&gt;#901327&lt;/a&gt; (tigervnc)&lt;/li&gt;
&lt;li&gt;uploaded a fix for
  &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=902279"&gt;#902279&lt;/a&gt;
  (youtube-dl) to DELAYED/3-day&lt;/li&gt;
&lt;li&gt;sent a patch for
  &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=902318"&gt;#902318&lt;/a&gt;
  (monkeysphere)&lt;/li&gt;
&lt;li&gt;was less hateful in
  &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=899060"&gt;#899060&lt;/a&gt;
  (monkeysphere)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href="http://clarete.li/"&gt;Lincoln&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Editor's note:&lt;/em&gt; Lincoln was a new Debian contributor and made lots of
progress! Thanks for joining us&amp;mdash;we're thrilled with your contributions
&amp;#x1F389; Here's his report.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Got my environment setup to work on packages again \o/&lt;/li&gt;
&lt;li&gt;Played with
  &lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=901318"&gt;901318&lt;/a&gt; for a
  while but didn't really make progress because it seems to be a long
  discussion so its bad for a newcomer&lt;/li&gt;
&lt;li&gt;Was indeed more successful on the python lands. Opened the following PRs&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Kronuz/pyScss/pull/374"&gt;Kronuz/pyScss#374&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ionelmc/pytest-benchmark/pull/114"&gt;ionelmc/pytest-benchmark#114&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Now working on uploading the patches to python-pyscss &amp;amp;
   python-pytest-benchmark packages removing the dependency on python-pathlib.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href="https://dkg.fifthhorseman.net/blog/"&gt;dkg&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;worked on debugging/diagnosing enigmail in preparation for making it
  DFSG-free again (see &lt;a href="https://bugs.debian.org/901556"&gt;#901556&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;got pointers from Lincoln about understanding flow control in
  asynchronous javascript for debugging the failing autopkgtest suites&lt;/li&gt;
&lt;li&gt;got pointers from Elana on emulating ci.debian.net's autopkgtest
  infrastructure so i have a better chance of replicating the failures
  seen on that platform&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Simon&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Moved python-requests-oauthlib to
  &lt;a href="https://salsa.debian.org/simonft-guest/python-requests-oauthlib"&gt;salsa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Updated it to 1.0 (new release), pending a couple final checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href="https://ldpreload.com"&gt;Geoffrey&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Worked with Lincoln on both bugs&lt;/li&gt;
&lt;li&gt;Opened &lt;a href="https://bugs.debian.org/902323"&gt;#902323&lt;/a&gt; about removing
  python-pathlib&lt;/li&gt;
&lt;li&gt;Working on new pymssql upstream release / restoring it to unstable&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;By the numbers&lt;/h2&gt;
&lt;p&gt;All in all, we completed 6 uploads, worked on 8 bugs, filed 3 bugs, submitted 3
patches or pull requests, and closed 2 bugs. Go us! Thanks to everyone for
contributing to a very productive effort.&lt;/p&gt;
&lt;p&gt;See you all next time.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Looking back on "Teaching Python: The Hard Parts"</title><link href="https://hashman.ca/pycon-2016-reflections/" rel="alternate"></link><published>2018-06-13T19:00:00-04:00</published><updated>2018-06-13T19:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-06-13:/pycon-2016-reflections/</id><summary type="html">&lt;p&gt;It's been over two years since I presented this talk at PyCon US. Is it still relevant? These are my thoughts on the Python 2 to 3 transition and more.&lt;/p&gt;</summary><content type="html">&lt;p&gt;One of my goals when writing talks is to produce content with a long shelf
life. Because I'm one of those weird people that prefers to write new talks for
new events, I feel like it'd be a waste of effort if my talks didn't at least
age well. So how do things measure up if I look back on one of my oldest?&lt;/p&gt;
&lt;p&gt;&lt;a href="/pycon-2016"&gt;"Teaching Python: The Hard Parts"&lt;/a&gt; remains one of my most popular
talks, despite presenting it just one time at PyCon US 2016. For most of the
past two years, it held steady as a top 10 talk from PyCon 2016 by popularity
on YouTube (although it was recently overtaken by a few hundred views
&amp;#x1F633;), even when counting it against the keynotes (!), and most of the
&lt;a href="https://www.youtube.com/watch?v=CjYEpVNbM-s#comments"&gt;YouTube comments&lt;/a&gt; are shockingly nice (!!).&lt;/p&gt;
&lt;h2&gt;Well, actually&lt;/h2&gt;
&lt;p&gt;Not everyone was a fan. &lt;em&gt;Obviously&lt;/em&gt; I should have known better than to tell
instructors they didn't have to use Python 3:&lt;/p&gt;
&lt;div style="text-align: center"&gt;
  &lt;img alt="Matt Williams: Obviously Python 3 should be taught over Python 2. In a few years time 2 will be completely unsupported http://pythonclock.org/"
       src="/images/angry_youtube_man.png" /&gt;
&lt;/div&gt;

&lt;p&gt;Did I give bad advice? Was mentiontioning the usability advantage of better
library support and documentation SEO with Python 2 worth the &lt;em&gt;irreparable
damage I might have done to the community?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Matt's not the only one with a chip on his shoulder: the Python 2 &amp;#x2192; 3
transition has been contentious, and much ink has been spilled on the topic. A
popular author infamously wrote a &lt;a href="https://donotlink.it/OKPM"&gt;long screed&lt;/a&gt; claiming "PYTHON 3 IS
SUCH A FAILURE IT WILL KILL PYTHON". &lt;strong&gt;Spoiler alert:&lt;/strong&gt; Python is still alive,
and the author updated his book for Python 3.&lt;/p&gt;
&lt;p&gt;I've now spent a few years writing 2/3 compatible code, and am on the cusp of
dropping Python 2 entirely. I've felt bad for not weighing in on the topic
publicly, because people might have looked to this talk for guidance and
wouldn't know my advice has changed over the past two years.&lt;/p&gt;
&lt;h3&gt;A little history&lt;/h3&gt;
&lt;p&gt;I wrote this talk based on my experiences teaching Python in the winter and
fall of 2014, and presented it in early 2016. Back then, it wasn't clear if
Python 3 adoption was going to pick up: Hynek wrote &lt;a href="https://hynek.me/articles/python3-2016/"&gt;an article about Python 3
adoption&lt;/a&gt; a few months before PyCon that contained the ominous
subheading "GLOOM". Python 3 &lt;a href="https://twitter.com/pycharm/status/865659029460209664"&gt;only reached a majority mindshare of Python
developers&lt;/a&gt; in May 2017!&lt;/p&gt;
&lt;p&gt;Why? That's a topic long enough to fill a series of blog posts, but briefly:
the number of breaking changes introduced in the first few releases in Python
3, coupled with the lack of compelling features to incentivize migration led to
slow adoption. &lt;a href="https://alexgaynor.net/2013/dec/30/about-python-3/"&gt;Personally, until the Python 3.3 release,&lt;/a&gt; I don't think
Python 3 had that balance right to really take off. Version 3.3 was &lt;a href="https://en.wikipedia.org/wiki/History_of_Python#Version_release_dates"&gt;released
in fall of 2012&lt;/a&gt;. Python 3.4 was only released in early 2014, just
before I mentored at my first set of workshops!&lt;/p&gt;
&lt;p&gt;This is a long-winded way to say, "when I gave this talk, it wasn't clear that
telling workshop organizers to teach Python 3 would be good advice, because the
ecosystem wasn't there yet."&lt;/p&gt;
&lt;h3&gt;The brave new world&lt;/h3&gt;
&lt;p&gt;But this is no longer the case! Python 3 adoption is overtaking Python 2 use,
&lt;a href="https://www.youtube.com/watch?v=66XoCk79kjM"&gt;even in the enterprise space&lt;/a&gt;. The &lt;a href="https://pythonclock.org/"&gt;Python 2 clock&lt;/a&gt; keeps on
ticking. Latest releases of Python 3 have compelling features to lure users,
including &lt;a href="https://docs.python.org/3/library/asyncio.html"&gt;strong, native concurrency support&lt;/a&gt;, &lt;a href="https://docs.python.org/3/reference/lexical_analysis.html#f-strings"&gt;formatted
strings&lt;/a&gt;, &lt;a href="https://www.python.org/dev/peps/pep-0519/"&gt;better cross-system path support&lt;/a&gt;, and &lt;a href="https://docs.python.org/3/library/typing.html"&gt;type
hints&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is to say, if I had to pick just one change to make to this talk if I gave
it today, I would tell folks&lt;/p&gt;
&lt;h2 style="text-align: center; color: black"&gt;USE PYTHON 3! &amp;#x2728;&lt;/h2&gt;

&lt;h3&gt;Other updates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://python-packaging.readthedocs.io/en/latest/"&gt;documentation for packaging Python&lt;/a&gt; is a lot better now.
  There have been &lt;a href="https://www.youtube.com/watch?v=qOH-h-EKKac"&gt;many&lt;/a&gt; &lt;a href="https://www.youtube.com/watch?v=AQsZsgJ30AE"&gt;good&lt;/a&gt; &lt;a href="https://www.youtube.com/watch?v=ASw2htNYa1E"&gt;talks&lt;/a&gt; presented on the
  subject.&lt;/li&gt;
&lt;li&gt;Distributing Python is still hard. There isn't a widely adopted practice for
  cross-platform management of compiled dependencies yet, although wheels are
  picking up steam. I'm currently working on the &lt;code&gt;manylinux2010&lt;/code&gt; update to
  address this problem on Linux systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Endorsements&lt;/h2&gt;
&lt;p&gt;Not to let one YouTube commenter rain on my parade, I am thrilled to say that
some people in the community have written some awfully nice things about my
talk. Thanks to all for doing so&amp;mdash;pulling this together really brightened
my day!&lt;/p&gt;
&lt;h3&gt;Blog Posts&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Roxanne Johnson&lt;/strong&gt; &lt;a href="http://roxjohnson.com/projects/2016/06/19/PyCon-Poster-Next-Steps.html"&gt;writes&lt;/a&gt;, "Elana Hashman’s PyCon talk on
Teaching Python: The Hard Parts had me nodding so hard I thought I might
actually be headbanging." &amp;#x1F604;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Georgia Reh&lt;/strong&gt; &lt;a href="http://georgiareh.com/2016/06/post-Pycon"&gt;writes&lt;/a&gt;, "I am just in love with this talk. Any
one who has seen me speak about teaching git knows I try really hard to not
overload students with information, and Elana has a very clear idea of what a
beginner needs to know when learning python versus what they can learn later."
&amp;#x1F496;&lt;/p&gt;
&lt;h3&gt;Tweets&lt;/h3&gt;
&lt;p&gt;When I presented this talk, I was too shy to attach my twitter handle to my
slides, so all these folks tweeted at me by name. Wow!&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;&lt;p lang="en" dir="ltr"&gt;Elana
Hashman&amp;#39;s talk on teaching programming has a lot of practical take-aways!
&lt;a href="https://twitter.com/pycon?ref_src=twsrc%5Etfw"&gt;@pycon&lt;/a&gt;  &lt;a
href="https://twitter.com/hashtag/pycon2016?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#pycon2016&lt;/a&gt;&lt;/p&gt;&amp;mdash;
Susan Tan (@ArcTanSusan) &lt;a
href="https://twitter.com/ArcTanSusan/status/737802727024001032?ref_src=twsrc%5Etfw"&gt;June
1, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;&lt;p lang="en" dir="ltr"&gt;Learned
a bunch from this video: Elana Hashman - Teaching Python: The Hard Parts -
PyCon 2016 :: &lt;a
href="https://t.co/IVeaq0XugJ"&gt;https://t.co/IVeaq0XugJ&lt;/a&gt;&lt;/p&gt;&amp;mdash; Mita
Williams (@copystar) &lt;a
href="https://twitter.com/copystar/status/738381708542771200?ref_src=twsrc%5Etfw"&gt;June
2, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;&lt;p lang="es" dir="ltr"&gt;Muy
buenos consejos en la presentación de Elana Hashman - Teaching Python: The Hard
Parts - &lt;a
href="https://twitter.com/hashtag/PyCon2016?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#PyCon2016&lt;/a&gt;
&lt;a href="https://t.co/5dhNX5KO8y"&gt;https://t.co/5dhNX5KO8y&lt;/a&gt;&lt;/p&gt;&amp;mdash; José
Carlos García (@quobit) &lt;a
href="https://twitter.com/quobit/status/741674289250881536?ref_src=twsrc%5Etfw"&gt;June
11, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;blockquote class="twitter-tweet tw-align-center" data-cards="hidden" data-lang="en" data-dnt="true"&gt;&lt;p
lang="en" dir="ltr"&gt;Elana cool talk! Explaining scope: maybe use analogy of
person having same name as a celebrity &lt;a
href="https://twitter.com/pycon?ref_src=twsrc%5Etfw"&gt;@pycon&lt;/a&gt; &lt;a
href="https://twitter.com/hashtag/pycon2016?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#pycon2016&lt;/a&gt;
&lt;a href="https://t.co/LAoGbY4uGO"&gt;https://t.co/LAoGbY4uGO&lt;/a&gt;&lt;/p&gt;&amp;mdash; robin
chauhan (@robinc) &lt;a
href="https://twitter.com/robinc/status/754753761256480769?ref_src=twsrc%5Etfw"&gt;July
17, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;blockquote class="twitter-tweet tw-align-center" data-cards="hidden" data-lang="en" data-dnt="true"&gt;&lt;p
lang="en" dir="ltr"&gt;If you&amp;#39;re about to teach a hands-on &lt;a
href="https://twitter.com/hashtag/Python?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#Python&lt;/a&gt;
workshop/tutorial/class, go watch Elana Hashman&amp;#39;s &lt;a
href="https://twitter.com/hashtag/pycon2016?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#pycon2016&lt;/a&gt;
talk 🎓🐍💖&lt;a
href="https://t.co/xVJ6YBKFtV"&gt;https://t.co/xVJ6YBKFtV&lt;/a&gt;&lt;/p&gt;&amp;mdash; ✨ Trey
Hunner 🐍 (@treyhunner) &lt;a
href="https://twitter.com/treyhunner/status/796941041547018240?ref_src=twsrc%5Etfw"&gt;November
11, 2016&lt;/a&gt;&lt;/blockquote&gt;

&lt;h3&gt;Other&lt;/h3&gt;
&lt;p&gt;My talk was included in the &lt;a href="https://github.com/quobit/awesome-python-in-education/blob/master/README.md#conferences-and-videos"&gt;"Awesome Python in Education" list&lt;/a&gt;.
How cool &amp;#x1F60E;&lt;/p&gt;
&lt;h2&gt;Declaring a small victory&lt;/h2&gt;
&lt;p&gt;Writing this post has convinced me that "Teaching Python: The Hard Parts" meets
some arbitrary criteria for "sufficiently forward-thinking." Much of the
content still strikes me as fresh: as an occasional mentor for various
technical workshops, I still keep running into trouble with platform diversity,
the command line, and packaging; the "general advice" section is evergreen for
Python and non-Python workshops alike. So with all that said, here's hoping
that looking back on this talk will keep it alive. &lt;a href="https://www.youtube.com/watch?v=CjYEpVNbM-s"&gt;Give it a watch&lt;/a&gt;
if you haven't seen it before!&lt;/p&gt;
&lt;p&gt;If you like what you see and you're interested in checking out my speaking
portfolio or would like to invite me to speak at your conference or event,
do check out my &lt;a href="/talks"&gt;talks&lt;/a&gt; page.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>I'm hosting a small Debian BSP in Brooklyn</title><link href="https://hashman.ca/nyc-bsp/" rel="alternate"></link><published>2018-06-02T15:20:00-04:00</published><updated>2018-06-02T15:20:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-06-02:/nyc-bsp/</id><summary type="html">&lt;p&gt;I'm hosting a Debian BSP on Sunday, June 24th at 61 Local in Brooklyn, NY, USA from 3pm to 8pm.&lt;/p&gt;</summary><content type="html">&lt;p&gt;The time has come for NYC Debian folks to gather. I've bravely volunteered to
host a &lt;a href="https://wiki.debian.org/BSP/2018/06/us/NYC"&gt;local bug squashing party&lt;/a&gt;
(or BSP) in late June.&lt;/p&gt;
&lt;h3&gt;Details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Venue:&lt;/strong&gt; &lt;a href="https://www.openstreetmap.org/node/3575097893"&gt;61 Local&lt;/a&gt;: 61
  Bergen St., Brooklyn, NY, USA&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More about the venue:&lt;/strong&gt; &lt;a href="http://61local.com/"&gt;website&lt;/a&gt;, good vegetarian
  options available&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Date:&lt;/strong&gt; Sunday, June 24, 2018&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start:&lt;/strong&gt; 3pm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;End:&lt;/strong&gt; 8pm or so&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RSVP:&lt;/strong&gt; &lt;a href="https://ti.to/nyc-dug/june-bsp"&gt;Please RSVP! Click here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;I'm an existing contributor, what should I work on?&lt;/h2&gt;
&lt;p&gt;The focus of this BSP is to give existing contributors some dedicated time to
work on their projects. I don't have a specific outcome in mind. I do not plan
on tagging bugs specifically for the BSP, but that shouldn't stop you from
doing so if you want to.&lt;/p&gt;
&lt;p&gt;Personally, I am going to spend some time on fixing the alternatives logic in
the &lt;code&gt;clojure&lt;/code&gt; and &lt;code&gt;clojure1.8&lt;/code&gt; packages.&lt;/p&gt;
&lt;p&gt;If you don't really have a project you want to work on, but you're interested
in helping mentor new contributors that show up, please &lt;a href="mailto:ehashman@debian.org"&gt;get in
touch&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;I'm a new contributor and want to join but I have no idea what I'm doing!&lt;/h2&gt;
&lt;p&gt;At some point, that was all of us!&lt;/p&gt;
&lt;p&gt;Even though this BSP is aimed at existing contributors, you are welcome to
attend! We'll have a dedicated mentor available to coordinate and help out new
contributors.&lt;/p&gt;
&lt;p&gt;If you've never contributed to Debian before, I recommend you check out &lt;a href="https://www.debian.org/intro/help"&gt;"How
can you help Debian?"&lt;/a&gt; and &lt;a href="https://wiki.debian.org/BSP/BeginnersHOWTO"&gt;the beginner's
HOWTO for BSPs&lt;/a&gt; in advance of the
BSP. I also wrote a
&lt;a href="https://wiki.debian.org/Clojure/PackagingTutorial"&gt;tutorial&lt;/a&gt; and &lt;a href="/debian-build-tools"&gt;blog
post&lt;/a&gt; on packaging that might help. Remember, you &lt;strong&gt;don't
have to code or build packages&lt;/strong&gt; to make valuable contributions!&lt;/p&gt;
&lt;h2&gt;See you there!&lt;/h2&gt;
&lt;p&gt;Happy hacking.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>A tale of three Debian build tools</title><link href="https://hashman.ca/debian-build-tools/" rel="alternate"></link><published>2018-04-03T00:00:00-04:00</published><updated>2018-04-03T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-04-03:/debian-build-tools/</id><summary type="html">&lt;p&gt;An overview of my Debian workflow, and how I use three different build tools to get the job done.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Many people have asked me about my Debian workflow. Which is funny, because
it's hard to believe that when you use three different build tools that you're
doing it right, but I &lt;em&gt;have&lt;/em&gt; figured out a process that works for me. I use
&lt;code&gt;git-buildpackage&lt;/code&gt; (&lt;code&gt;gbp&lt;/code&gt;), &lt;code&gt;sbuild&lt;/code&gt;, and &lt;code&gt;pbuilder&lt;/code&gt;, each for different
purposes. Let me describe why and how I use each, and the possible downsides of
each tool.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This blog post is aimed at people already familiar with Debian
packaging, particularly using &lt;code&gt;Vcs-Git&lt;/code&gt;. If you'd like to learn more about the
basics of Debian packaging, I recommend you check out my &lt;a href="https://wiki.debian.org/Clojure/PackagingTutorial"&gt;Clojure Packaging
Tutorial&lt;/a&gt; and my &lt;a href="/clojuresync/"&gt;talk about
packaging Leiningen&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;git-buildpackage&lt;/code&gt;: the workhorse&lt;/h2&gt;
&lt;p&gt;I use &lt;a href="http://honk.sigxcpu.org/projects/git-buildpackage/manual-html/"&gt;&lt;code&gt;git-buildpackage&lt;/code&gt;&lt;/a&gt; (aka &lt;code&gt;gbp&lt;/code&gt;) to do the majority of my package
builds.  Because it runs by default without any special sandboxing from your
base system, &lt;code&gt;gbp&lt;/code&gt; builds things &lt;em&gt;fast&lt;/em&gt;&amp;mdash;much faster than other build
tools&amp;mdash;and as such, it's a great tool if you are iterating quickly to work
bugs out of a build.&lt;/p&gt;
&lt;p&gt;I usually invoke &lt;code&gt;gbp&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gbp&lt;span class="w"&gt; &lt;/span&gt;buildpackage&lt;span class="w"&gt; &lt;/span&gt;-uc&lt;span class="w"&gt; &lt;/span&gt;-us
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The flags ensure that 1) we don't sign the .changes file generated (&lt;code&gt;-uc&lt;/code&gt;) 2)
we don't sign the .dsc file (&lt;code&gt;-us&lt;/code&gt;), since typically I only want to sign build
artifacts right before upload.&lt;/p&gt;
&lt;p&gt;Other handy flags include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--git-ignore-new&lt;/code&gt;, which proceeds with a build even when you have an unclean
  working tree&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--git-ignore-branch&lt;/code&gt;, to build when you've checked out a branch that's not
  &lt;code&gt;master&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--git-pristine-tar&lt;/code&gt;, to automatically check out and build with the
  corresponding pristine tar checked into the repository&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Typically, if I use &lt;code&gt;gbp&lt;/code&gt; to build binary packages, I will only do so in the
confines of an updated, minimal sid LXC container, in order to reduce the risk
of contaminating my build with stuff that's not available in a clean build
environment.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gbp&lt;/code&gt; tastes great with &lt;a href="https://manpages.debian.org/stretch/devscripts/sadt.1.en.html"&gt;&lt;code&gt;sadt&lt;/code&gt;&lt;/a&gt;, a script in &lt;code&gt;devscripts&lt;/code&gt; that runs your
package's &lt;a href="https://people.debian.org/~mpitt/autopkgtest/README.package-tests.html"&gt;autopkgtests&lt;/a&gt; directly on your base system without
root. You will need to install your test package and any dependencies before
you can run &lt;code&gt;sadt&lt;/code&gt;, but it requires much less setup and infrastructure than
&lt;code&gt;autopkgtest&lt;/code&gt; does.&lt;/p&gt;
&lt;div style="text-align:center"&gt;&lt;strong&gt;***&lt;/strong&gt;&lt;/div&gt;

&lt;p&gt;So while &lt;code&gt;gbp&lt;/code&gt; is awesome for the majority of my development workflow, I don't
rely on the output of &lt;code&gt;gbp&lt;/code&gt; when I want to upload a package, however clean I
think my build LXC is. For uploads, I still use &lt;code&gt;gbp&lt;/code&gt;, but exclusively to
perform source-only (&lt;code&gt;-S&lt;/code&gt;) builds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gbp&lt;span class="w"&gt; &lt;/span&gt;buildpackage&lt;span class="w"&gt; &lt;/span&gt;-S&lt;span class="w"&gt; &lt;/span&gt;-uc&lt;span class="w"&gt; &lt;/span&gt;-us
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Sometimes I may also need to pass the &lt;code&gt;-d&lt;/code&gt; flag when building source packages
to ignore installed build dependencies. By default, &lt;code&gt;gbp&lt;/code&gt; won't proceed with a
build when build dependencies are not installed, but when a said dependency is
only needed for building the binary (and not the source) package, we can safely override this check.&lt;/p&gt;
&lt;p&gt;Typically, when I'm uploading an update to a package, I'll just build the
source package with &lt;code&gt;gbp&lt;/code&gt; as above, sign the .changes and .dsc files, and
complete a source-only upload so the buildds can handle all the build details.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;sbuild&lt;/code&gt;: the gating build&lt;/h2&gt;
&lt;p&gt;"But wait!" you undoubtedly object. "How do you know your source package isn't
full of garbage?!" That's a great question, because... I don't. So it behooves
me to test it. And since the buildds use &lt;a href="https://wiki.debian.org/sbuild"&gt;&lt;code&gt;sbuild&lt;/code&gt;&lt;/a&gt;, why not use that
for my own QA?&lt;/p&gt;
&lt;p&gt;Setting up &lt;code&gt;sbuild&lt;/code&gt; is a giant pain. You need a machine you have root access
on, which wasn't the case for &lt;code&gt;git-buildpackage&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To use &lt;code&gt;sbuild&lt;/code&gt; without sudo, you'll need to add your user to the &lt;code&gt;sbuild&lt;/code&gt;
group:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;sbuild-adduser&lt;span class="w"&gt; &lt;/span&gt;myusername
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And create a schroot for builds:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;sbuild-createchroot&lt;span class="w"&gt; &lt;/span&gt;unstable&lt;span class="w"&gt; &lt;/span&gt;/srv/chroot/unstable-amd64-sbuild&lt;span class="w"&gt; &lt;/span&gt;http://deb.debian.org/debian
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you ever need to update your &lt;code&gt;sbuild&lt;/code&gt; schroot (you will), you can run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;sbuild-update&lt;span class="w"&gt; &lt;/span&gt;-udcar&lt;span class="w"&gt; &lt;/span&gt;unstable-amd64-sbuild
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I remember these flags by pronouncing them as one word, "ud-car", which sounds
absurd and is hence memorable. I can never remember the name of my schroot, but
I can look that up by running &lt;code&gt;ls /srv/chroot&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Okay, time to build. Once we have our source package from &lt;code&gt;gbp&lt;/code&gt;, we should have
a .dsc file to pass to &lt;code&gt;sbuild&lt;/code&gt;. We can build like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sbuild&lt;span class="w"&gt; &lt;/span&gt;mypackage_1.0-1.dsc&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;unstable&lt;span class="w"&gt; &lt;/span&gt;-A&lt;span class="w"&gt; &lt;/span&gt;--run-autopkgtest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We specify the target distribution with &lt;code&gt;-d unstable&lt;/code&gt;, and &lt;code&gt;-A&lt;/code&gt; ensures that
our "arch: all" package will actually build (not necessary if your package
targets specific architectures). To run the autopkgtests after a successful
build, we pass &lt;code&gt;--run-autopkgtest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I don't like typing very much so I stick all these parameters in an &lt;code&gt;.sbuildrc&lt;/code&gt;
in my home directory. You can reference or copy the one in
&lt;code&gt;/usr/share/doc/sbuild/examples/example.sbuildrc&lt;/code&gt; because it's a Perl script
that ends in &lt;code&gt;1;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I add&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;$distribution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;unstable&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$build_arch_all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;# Optionally enable running autopkgtests&lt;/span&gt;
&lt;span class="c1"&gt;# $run_autopkgtest = 1;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;so I don't have to type these in all the time. I don't enable autopkgtests by
default because they prompt for a sudo password midway through the build (but
perhaps that won't bother you, so feel free to uncomment those lines). Once we
have our &lt;code&gt;~/.sbuildrc&lt;/code&gt; created, then we can just run&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sbuild&lt;span class="w"&gt; &lt;/span&gt;mypackage_1.0-1.dsc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Much better!&lt;/p&gt;
&lt;p&gt;After my package successfully builds and tests, I take a quick look at the
changes, build environment, and package contents. &lt;code&gt;sbuild&lt;/code&gt; automatically prints
these out, which is very convenient. If everything looks okay, I will sign the
source package with &lt;a href="https://manpages.debian.org/stretch/devscripts/debsign.1.en.html"&gt;&lt;code&gt;debsign&lt;/code&gt;&lt;/a&gt; and upload it with &lt;a href="https://manpages.debian.org/stretch/dput-ng/dput.1.en.html"&gt;&lt;code&gt;dput&lt;/code&gt;&lt;/a&gt;
(from &lt;code&gt;dput-ng&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;pbuilder&lt;/code&gt;: I need to upload binaries!&lt;/h2&gt;
&lt;p&gt;One irritation I have with &lt;code&gt;sbuild&lt;/code&gt; is I can never figure out the right flags
to get the right build artifacts to do a binary upload. Its defaults are too
minimal for sending to NEW without some additional fancy incantations (it
doesn't include the package tarball, only the buildinfo and produced .deb), and
I have a hard enough time remembering the flags that I listed above. Remember,
this is what the manpage for &lt;code&gt;sbuild&lt;/code&gt; looks like:&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;MANPAGE OF THE DAY: sbuild
  &lt;a href="https://t.co/e7nwB5PUUZ"&gt;https://t.co/e7nwB5PUUZ&lt;/a&gt;
  &lt;br&gt;&lt;br&gt;
  ...this was a little traumatizing tbh
  &lt;a href="https://t.co/zSSEbe4ROH"&gt;pic.twitter.com/zSSEbe4ROH&lt;/a&gt;
 &lt;/p&gt;
 &amp;mdash; e. hashman (@ehashdn)
 &lt;a href="https://twitter.com/ehashdn/status/944771961367998464?ref_src=twsrc%5Etfw"&gt;December 24, 2017&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;p&gt;So when I have to upload a NEW package, I usually use &lt;a href="https://pbuilder.alioth.debian.org/"&gt;&lt;code&gt;pbuilder&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are two ways to invoke &lt;code&gt;pbuilder&lt;/code&gt;. The first is the easiest, but "not
recommended" for uploads by the manpage: simply navigate to the root of the
repository you want to build and run &lt;code&gt;pdebuild&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pdebuild
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wow, that's the simplest thing we've run yet! Why don't we run it all the
time?! Well, because of the way &lt;code&gt;pbuilder&lt;/code&gt; sets up its filesystem, it can be
slower than &lt;code&gt;sbuild&lt;/code&gt;, so I've moved it out of my development workflow. It also
requires my sudo password, and as I mentioned earlier, I don't particularly
like having to enter that mid-build.&lt;/p&gt;
&lt;p&gt;The second way I usually apply when I need to upload a build: invoking
&lt;code&gt;pbuilder&lt;/code&gt; directly. Like with &lt;code&gt;sbuild&lt;/code&gt;, we need to provide it a .dsc, so we
should build a source package first. However, &lt;code&gt;pbuilder&lt;/code&gt; is smarter than
&lt;code&gt;sbuild&lt;/code&gt; and doesn't need me to give it architectures and target distros and
whatnot, so there is significantly less headache if I haven't tweaked a
personal configuration. With &lt;code&gt;pbuilder&lt;/code&gt;, I can run&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;pbuilder&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;mypackage_1.0-1.dsc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and I get a package!&lt;/p&gt;
&lt;p&gt;One of the annoying things about &lt;code&gt;pbuilder&lt;/code&gt; is that it doesn't output files in
my current build directory. Instead, by default, it places build artifacts
inside &lt;code&gt;/var/cache/pbuilder/result&lt;/code&gt;. So I always have to remember to copy
things out of there before I upload.&lt;/p&gt;
&lt;p&gt;Also, &lt;code&gt;pbuilder&lt;/code&gt; doesn't print out some build information that I should check
over before uploading, so I have to do that manually with &lt;a href="https://manpages.debian.org/stretch/dpkg/dpkg.1.en.html"&gt;&lt;code&gt;dpkg&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Print out package information, including dependencies&lt;/span&gt;
dpkg&lt;span class="w"&gt; &lt;/span&gt;-I&lt;span class="w"&gt; &lt;/span&gt;libmypackage_1.0-1_all.deb

&lt;span class="c1"&gt;# List all contents of the package&lt;/span&gt;
dpkg&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;libmypackage_1.0-1_all.deb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now I can go ahead and sign my built .changes file and perform an upload!&lt;/p&gt;
&lt;h2&gt;In summary&lt;/h2&gt;
&lt;p&gt;Here are what I'd say the pros and cons of each of these three build tools I
run are.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;git-buildpackage&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Super speedy (gotta go fast)&lt;/li&gt;
&lt;li&gt;Uses version control&lt;/li&gt;
&lt;li&gt;No rootz&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Way too much typing&lt;/li&gt;
&lt;li&gt;Constantly have to run &lt;code&gt;d/rules clean&lt;/code&gt; or pass &lt;code&gt;--git-ignore-new&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Can't produce production build artifacts&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;sbuild&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Supposedly "fast"&lt;/li&gt;
&lt;li&gt;Prints helpful information once the build is complete&lt;/li&gt;
&lt;li&gt;Runs autopkgtests with no marginal effort&lt;/li&gt;
&lt;li&gt;Only needs root like every third time I run it&lt;/li&gt;
&lt;li&gt;Conforms with the buildds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setup is way too complicated&lt;/li&gt;
&lt;li&gt;Manpage is terrifying&lt;/li&gt;
&lt;li&gt;Doesn't actually give me the build artifacts I want&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;code&gt;pbuilder&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The least typing!!!&lt;/li&gt;
&lt;li&gt;Gets me all the build artifacts I want&lt;/li&gt;
&lt;li&gt;Not the reason I get rejected by FTP Master&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slow&lt;/li&gt;
&lt;li&gt;Sticks build artifacts into /var/run/wheretheheck&lt;/li&gt;
&lt;li&gt;People will yell at you for not using &lt;code&gt;sbuild&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;cowbuilder, qemubuilder, whalebuilder, mylittlepersonalbuilder, etc.&lt;/h3&gt;
&lt;p&gt;Pros:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I don't use these.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I don't use these.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hope you enjoyed the tour. Happy building!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git-buildpackage&lt;/code&gt; &lt;a href="http://honk.sigxcpu.org/projects/git-buildpackage/manual-html/"&gt;homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sadt&lt;/code&gt; &lt;a href="https://manpages.debian.org/stretch/devscripts/sadt.1.en.html"&gt;manpage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;autopkgtest&lt;/code&gt; &lt;a href="https://people.debian.org/~mpitt/autopkgtest/README.package-tests.html"&gt;homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sbuild&lt;/code&gt; &lt;a href="https://wiki.debian.org/sbuild"&gt;wiki page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;debsign&lt;/code&gt; &lt;a href="https://manpages.debian.org/stretch/devscripts/debsign.1.en.html"&gt;manpage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dput&lt;/code&gt; &lt;a href="https://manpages.debian.org/stretch/dput-ng/dput.1.en.html"&gt;manpage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pbuilder&lt;/code&gt; &lt;a href="https://pbuilder.alioth.debian.org/"&gt;homepage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dpkg&lt;/code&gt; &lt;a href="https://manpages.debian.org/stretch/dpkg/dpkg.1.en.html"&gt;manpage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="blog"></category></entry><entry><title>ClojureSYNC Talk Resources</title><link href="https://hashman.ca/clojuresync/" rel="alternate"></link><published>2018-03-17T00:00:00-04:00</published><updated>2018-03-17T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-03-17:/clojuresync/</id><summary type="html">&lt;p&gt;Talk resources for "&lt;code&gt;apt-get install leiningen&lt;/code&gt;: Bootstrapping the Clojure Ecosystem for Debian", presented at the inaugural ClojureSYNC.&lt;/p&gt;</summary><content type="html">&lt;p&gt;At the inaugural &lt;a href="https://clojuresync.com/"&gt;ClojureSYNC&lt;/a&gt; in 2018, I gave a talk called "&lt;code&gt;apt-get
install leiningen&lt;/code&gt;: Bootstrapping the Clojure Ecosystem for Debian". This was
the culmination of the year of work I put into packaging Leiningen 2.x and
other Clojure software for Debian.&lt;/p&gt;
&lt;p&gt;It was incredibly exciting to present there, and Eric ran a fabulous
conference! I wish more tech conferences would send me to New Orleans.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;apt-get install leiningen&lt;/code&gt;: Bootstrapping the Clojure Ecosystem for Debian&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://clojuresync.com/elana-hashman/"&gt;Talk page, ClojureSYNC website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Talk video: posted at the link above&lt;/li&gt;
&lt;li&gt;&lt;a href="/clojuresync/clojuresync-ehashman.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://qa.debian.org/developer.php?login=debian%40hashman.ca+ehashman&amp;amp;comaint=yes"&gt;All the packages I maintain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salsa.debian.org/clojure-team"&gt;Clojure Team's GitLab repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.debian.org/Clojure"&gt;Debian Clojure Wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.debian.org/Clojure/PackagingTutorial"&gt;Debian Clojure Packaging Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Follow-up readings&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://danluu.com/web-bloat/"&gt;How web bloat affects people with slow connections&lt;/a&gt;, by Dan Luu&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ashedryden.com/blog/the-ethics-of-unpaid-labor-and-the-oss-community"&gt;The Ethics of Unpaid Labor and the OSS Community&lt;/a&gt;, by Ashe Dryden&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.debian.org/social_contract"&gt;Debian Social Contract&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.debian.org/social_contract#guidelines"&gt;Debian Free Software Guidelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lwn.net/Articles/201488/"&gt;Debian Dunc-Tank Controversy&lt;/a&gt; via LWN&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Image licensing info&lt;/h3&gt;
&lt;p&gt;"There's no NEW queue for talk slides." &amp;ndash; lamby, Debian Project Leader&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debian logo, copyright 1999 &lt;a href="https://www.debian.org/logos/"&gt;Software in the Public Interest,
  Inc.&lt;/a&gt; used under the &lt;a href="http://creativecommons.org/licenses/by-sa/3.0/"&gt;Attribution-ShareAlike 3.0 Unported
  License&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Images on "The '90s" and "Walnut Creek GIFs Galore CDROM" slides were
  obtained from &lt;a href="https://archive.org/details/GifsGalore_Aug92"&gt;The Internet Archive&lt;/a&gt; and included under their &lt;a href="https://archive.org/about/terms.php"&gt;Terms of
  Use&lt;/a&gt;. It is believed the inclusion of these images, for
  illustration of the history of computing and file distribution, constitutes
  fair use under US copyright law.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/graphics/bwcartoon.html"&gt;Dynamic Duo: the Gnu and the Penguin in flight&lt;/a&gt; in colour, used under
  the &lt;a href="https://www.gnu.org/licenses/fdl-1.3.en.html"&gt;GNU Free Documentation License, v1.3&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/File:Yggdrasil-linux-summer-94.JPG"&gt;Yggdrasil Computing Plug and Play Linux&lt;/a&gt; was obtained from
  Wikipedia.  It is believed the inclusion of this image, for illustration of
  the history of early Linux distributions, constitutes fair use under US
  copyright law.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://commons.wikimedia.org/wiki/File:DebianFamilyTree1210.svg"&gt;Debian family tree&lt;/a&gt;, authors Andreas Lundqvist, Donjan Rodic,
  modified by &lt;a href="https://commons.wikimedia.org/wiki/User:Michaeldsuarez"&gt;Michaeldsuarez&lt;/a&gt;, used under the
  &lt;a href="https://www.gnu.org/licenses/fdl-1.3.en.html"&gt;GNU Free Documentation License, v1.3&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</content><category term="talks"></category></entry><entry><title>Stop streaming music from YouTube with this one weird trick</title><link href="https://hashman.ca/youtube-dl/" rel="alternate"></link><published>2018-03-07T00:00:00-05:00</published><updated>2018-03-07T00:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2018-03-07:/youtube-dl/</id><summary type="html">&lt;p&gt;Learn to use youtube-dl and ffmpeg to download and process audio you'd normally stream! &amp;#x1F3B6;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Having grown up on the internet long before the average connection speed made
music streaming services viable, streaming has always struck me as wasteful.
And I know that doesn't make much sense&amp;mdash;it's not like there's a limited
amount of bandwidth to go around! But if I'm going to listen to the same audio
file five times, why not just download it once and listen to it forever?
Particularly if I want to listen to it while airborne and avoid the horrors of
plane wifi. Or if I want to remove NSFW graphics that seem to frequently
accompany mixes I enjoy.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;youtube-dl&lt;/code&gt; to the rescue&lt;/h2&gt;
&lt;p&gt;Luckily, at least as far as YouTube audio is concerned, there is plenty of free
software available to help with this! I like to fetch and process music from
YouTube using &lt;a href="http://rg3.github.io/youtube-dl/"&gt;youtube-dl&lt;/a&gt; and
&lt;a href="https://ffmpeg.org/"&gt;ffmpeg&lt;/a&gt;. Both are packaged and available in Debian if you
like to &lt;code&gt;apt install&lt;/code&gt; things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://packages.debian.org/stretch/youtube-dl"&gt;youtube-dl package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://packages.debian.org/stretch/ffmpeg"&gt;ffmpeg package&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Saving audio files from YouTube&lt;/h2&gt;
&lt;p&gt;Well, let's suppose you want to download &lt;a href="https://www.youtube.com/watch?v=8B4guKLlbVU"&gt;some eurobeat&lt;/a&gt;. &lt;code&gt;youtube-dl&lt;/code&gt; can
help. The &lt;code&gt;-x&lt;/code&gt; flag tells &lt;code&gt;youtube-dl&lt;/code&gt; to skip downloading video and to only
fetch audio.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;youtube-dl&lt;span class="w"&gt; &lt;/span&gt;-x&lt;span class="w"&gt; &lt;/span&gt;https://www.youtube.com/watch?v&lt;span class="o"&gt;=&lt;/span&gt;8B4guKLlbVU
&lt;span class="o"&gt;[&lt;/span&gt;youtube&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8B4guKLlbVU:&lt;span class="w"&gt; &lt;/span&gt;Downloading&lt;span class="w"&gt; &lt;/span&gt;webpage
&lt;span class="o"&gt;[&lt;/span&gt;youtube&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8B4guKLlbVU:&lt;span class="w"&gt; &lt;/span&gt;Downloading&lt;span class="w"&gt; &lt;/span&gt;video&lt;span class="w"&gt; &lt;/span&gt;info&lt;span class="w"&gt; &lt;/span&gt;webpage
&lt;span class="o"&gt;[&lt;/span&gt;youtube&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8B4guKLlbVU:&lt;span class="w"&gt; &lt;/span&gt;Extracting&lt;span class="w"&gt; &lt;/span&gt;video&lt;span class="w"&gt; &lt;/span&gt;information
&lt;span class="o"&gt;[&lt;/span&gt;youtube&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;8B4guKLlbVU:&lt;span class="w"&gt; &lt;/span&gt;Downloading&lt;span class="w"&gt; &lt;/span&gt;js&lt;span class="w"&gt; &lt;/span&gt;player&lt;span class="w"&gt; &lt;/span&gt;vflGUPF-i
&lt;span class="o"&gt;[&lt;/span&gt;download&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Destination:&lt;span class="w"&gt; &lt;/span&gt;SUPER&lt;span class="w"&gt; &lt;/span&gt;EUROBEAT&lt;span class="w"&gt; &lt;/span&gt;MIX-8B4guKLlbVU.webm
&lt;span class="o"&gt;[&lt;/span&gt;download&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;.68MiB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;:57
Deleting&lt;span class="w"&gt; &lt;/span&gt;original&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;SUPER&lt;span class="w"&gt; &lt;/span&gt;EUROBEAT&lt;span class="w"&gt; &lt;/span&gt;MIX-8B4guKLlbVU.webm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;pass&lt;span class="w"&gt; &lt;/span&gt;-k&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;keep&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;YouTube sometimes throttles connections to approximate real-time buffer rates,
so the download could take a while. If you need to interrupt the download for
some reason, you can use &lt;code&gt;SIGINT&lt;/code&gt; (&lt;code&gt;Ctrl+C&lt;/code&gt;) to stop it. If you run
&lt;code&gt;youtube-dl&lt;/code&gt; again, it's smart enough to resume the download where you left
off. &lt;/p&gt;
&lt;p&gt;Once the download is complete, there's not much more to do. It will be saved
with the appropriate file extension so you can determine what audio codec it
uses. You might want to rename the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;mv&lt;span class="w"&gt; &lt;/span&gt;SUPER&lt;span class="se"&gt;\ &lt;/span&gt;EUROBEAT&lt;span class="se"&gt;\ &lt;/span&gt;MIX-8B4guKLlbVU.ogg&lt;span class="w"&gt; &lt;/span&gt;super_eurobeat_mix.ogg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can enjoy many plays of our &lt;code&gt;super_eurobeat_mix.ogg&lt;/code&gt; file!
&amp;#x1F697;&amp;#x1F3B6;&lt;/p&gt;
&lt;h2&gt;Re-encoding audio to another format&lt;/h2&gt;
&lt;p&gt;Suppose that I have a really old MP3 player I'd like to put this file on, and
it doesn't support the OGG Vorbis format. That's not a problem; we can use
&lt;code&gt;ffmpeg&lt;/code&gt; to re-encode the audio.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-i&lt;/code&gt; flag to &lt;code&gt;ffmpeg&lt;/code&gt; specifies an input file. &lt;code&gt;-acodec mp3&lt;/code&gt; says that we
want to use the mp3 codec to re-encode our audio. The last positional argument,
&lt;code&gt;super_eurobeat_mix.mp3&lt;/code&gt;, is the name of the file we want to output.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;ffmpeg&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;super_eurobeat_mix.ogg&lt;span class="w"&gt; &lt;/span&gt;-acodec&lt;span class="w"&gt; &lt;/span&gt;mp3&lt;span class="w"&gt; &lt;/span&gt;super_eurobeat_mix.mp3
ffmpeg&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.4.2-1+b1&lt;span class="w"&gt; &lt;/span&gt;Copyright&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2000&lt;/span&gt;-2018&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;FFmpeg&lt;span class="w"&gt; &lt;/span&gt;developers
&lt;span class="w"&gt;  &lt;/span&gt;built&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Debian&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.3.0-4&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;configuration:&lt;span class="w"&gt; &lt;/span&gt;--prefix&lt;span class="o"&gt;=&lt;/span&gt;/usr&lt;span class="w"&gt; &lt;/span&gt;--extra-version&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;+b1&lt;span class="w"&gt; &lt;/span&gt;--toolchain&lt;span class="o"&gt;=&lt;/span&gt;hardened
&lt;span class="w"&gt; &lt;/span&gt;--libdir&lt;span class="o"&gt;=&lt;/span&gt;/usr/lib/x86_64-linux-gnu&lt;span class="w"&gt; &lt;/span&gt;--incdir&lt;span class="o"&gt;=&lt;/span&gt;/usr/include/x86_64-linux-gnu
&lt;span class="w"&gt; &lt;/span&gt;--enable-gpl&lt;span class="w"&gt; &lt;/span&gt;--disable-stripping&lt;span class="w"&gt; &lt;/span&gt;--enable-avresample&lt;span class="w"&gt; &lt;/span&gt;--enable-avisynth
&lt;span class="w"&gt; &lt;/span&gt;--enable-gnutls&lt;span class="w"&gt; &lt;/span&gt;--enable-ladspa&lt;span class="w"&gt; &lt;/span&gt;--enable-libass&lt;span class="w"&gt; &lt;/span&gt;--enable-libbluray
&lt;span class="w"&gt; &lt;/span&gt;--enable-libbs2b&lt;span class="w"&gt; &lt;/span&gt;--enable-libcaca&lt;span class="w"&gt; &lt;/span&gt;--enable-libcdio&lt;span class="w"&gt; &lt;/span&gt;--enable-libflite
&lt;span class="w"&gt; &lt;/span&gt;--enable-libfontconfig&lt;span class="w"&gt; &lt;/span&gt;--enable-libfreetype&lt;span class="w"&gt; &lt;/span&gt;--enable-libfribidi&lt;span class="w"&gt; &lt;/span&gt;--enable-libgme
&lt;span class="w"&gt; &lt;/span&gt;--enable-libgsm&lt;span class="w"&gt; &lt;/span&gt;--enable-libmp3lame&lt;span class="w"&gt; &lt;/span&gt;--enable-libmysofa&lt;span class="w"&gt; &lt;/span&gt;--enable-libopenjpeg
&lt;span class="w"&gt; &lt;/span&gt;--enable-libopenmpt&lt;span class="w"&gt; &lt;/span&gt;--enable-libopus&lt;span class="w"&gt; &lt;/span&gt;--enable-libpulse&lt;span class="w"&gt; &lt;/span&gt;--enable-librubberband
&lt;span class="w"&gt; &lt;/span&gt;--enable-librsvg&lt;span class="w"&gt; &lt;/span&gt;--enable-libshine&lt;span class="w"&gt; &lt;/span&gt;--enable-libsnappy&lt;span class="w"&gt; &lt;/span&gt;--enable-libsoxr
&lt;span class="w"&gt; &lt;/span&gt;--enable-libspeex&lt;span class="w"&gt; &lt;/span&gt;--enable-libssh&lt;span class="w"&gt; &lt;/span&gt;--enable-libtheora&lt;span class="w"&gt; &lt;/span&gt;--enable-libtwolame
&lt;span class="w"&gt; &lt;/span&gt;--enable-libvorbis&lt;span class="w"&gt; &lt;/span&gt;--enable-libvpx&lt;span class="w"&gt; &lt;/span&gt;--enable-libwavpack&lt;span class="w"&gt; &lt;/span&gt;--enable-libwebp
&lt;span class="w"&gt; &lt;/span&gt;--enable-libx265&lt;span class="w"&gt; &lt;/span&gt;--enable-libxml2&lt;span class="w"&gt; &lt;/span&gt;--enable-libxvid&lt;span class="w"&gt; &lt;/span&gt;--enable-libzmq
&lt;span class="w"&gt; &lt;/span&gt;--enable-libzvbi&lt;span class="w"&gt; &lt;/span&gt;--enable-omx&lt;span class="w"&gt; &lt;/span&gt;--enable-openal&lt;span class="w"&gt; &lt;/span&gt;--enable-opengl&lt;span class="w"&gt; &lt;/span&gt;--enable-sdl2
&lt;span class="w"&gt; &lt;/span&gt;--enable-libdc1394&lt;span class="w"&gt; &lt;/span&gt;--enable-libdrm&lt;span class="w"&gt; &lt;/span&gt;--enable-libiec61883&lt;span class="w"&gt; &lt;/span&gt;--enable-chromaprint
&lt;span class="w"&gt; &lt;/span&gt;--enable-frei0r&lt;span class="w"&gt; &lt;/span&gt;--enable-libopencv&lt;span class="w"&gt; &lt;/span&gt;--enable-libx264&lt;span class="w"&gt; &lt;/span&gt;--enable-shared
&lt;span class="w"&gt;  &lt;/span&gt;libavutil&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;78&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;78&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavcodec&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.107.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.107.100
&lt;span class="w"&gt;  &lt;/span&gt;libavformat&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;83&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;83&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavdevice&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavfilter&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;.107.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;.107.100
&lt;span class="w"&gt;  &lt;/span&gt;libavresample&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;libswscale&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libswresample&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libpostproc&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;54&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;54&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.100
Input&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0, ogg, from &amp;#39;super_eurobeat_mix.ogg&amp;#39;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Duration:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.57,&lt;span class="w"&gt; &lt;/span&gt;start:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.000000,&lt;span class="w"&gt; &lt;/span&gt;bitrate:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;124&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kb/s
&lt;span class="w"&gt;    &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:0(eng): Audio: vorbis, 44100 Hz, stereo, fltp, 128 kb/s&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Metadata:
&lt;span class="w"&gt;      &lt;/span&gt;LANGUAGE&lt;span class="w"&gt;        &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;eng
&lt;span class="w"&gt;      &lt;/span&gt;ENCODER&lt;span class="w"&gt;         &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Lavf57.83.100
Stream&lt;span class="w"&gt; &lt;/span&gt;mapping:
&lt;span class="w"&gt;  &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:0 -&amp;gt; #0:0 (vorbis (native) -&amp;gt; mp3 (libmp3lame))&lt;/span&gt;
Press&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;q&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;stop,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;?&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;help&lt;/span&gt;
Output&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0, mp3, to &amp;#39;super_eurobeat_mix.mp3&amp;#39;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Metadata:
&lt;span class="w"&gt;    &lt;/span&gt;TSSE&lt;span class="w"&gt;            &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Lavf57.83.100
&lt;span class="w"&gt;    &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:0(eng): Audio: mp3 (libmp3lame), 44100 Hz, stereo, fltp&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Metadata:
&lt;span class="w"&gt;      &lt;/span&gt;LANGUAGE&lt;span class="w"&gt;        &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;eng
&lt;span class="w"&gt;      &lt;/span&gt;encoder&lt;span class="w"&gt;         &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Lavc57.107.100&lt;span class="w"&gt; &lt;/span&gt;libmp3lame
&lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;62432kB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.58&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bitrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;128&lt;/span&gt;.0kbits/s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;22&lt;/span&gt;.4x&lt;span class="w"&gt;    &lt;/span&gt;
video:0kB&lt;span class="w"&gt; &lt;/span&gt;audio:62431kB&lt;span class="w"&gt; &lt;/span&gt;subtitle:0kB&lt;span class="w"&gt; &lt;/span&gt;other&lt;span class="w"&gt; &lt;/span&gt;streams:0kB&lt;span class="w"&gt; &lt;/span&gt;global&lt;span class="w"&gt; &lt;/span&gt;headers:0kB
muxing&lt;span class="w"&gt; &lt;/span&gt;overhead:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.000396%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Voila! We now have a &lt;code&gt;super_eurobeat_mix.mp3&lt;/code&gt; file we can copy to our janky old
MP3 player.&lt;/p&gt;
&lt;h2&gt;Extracting audio from an existing video file&lt;/h2&gt;
&lt;p&gt;Sometimes I accidentally forget to pass the &lt;code&gt;-x&lt;/code&gt; flag to &lt;code&gt;youtube-dl&lt;/code&gt;,
and get a video file instead of an audio track. Oops.&lt;/p&gt;
&lt;p&gt;But that's okay! Extracting the audio track from the video file with &lt;code&gt;ffmpeg&lt;/code&gt;
is just a couple of commands away.&lt;/p&gt;
&lt;p&gt;First, we should determine the encoding of the audio track. The combined video
file is a .webm file, but we can peek inside using &lt;code&gt;ffmpeg&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;ffmpeg&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;SUPER&lt;span class="se"&gt;\ &lt;/span&gt;EUROBEAT&lt;span class="se"&gt;\ &lt;/span&gt;MIX-8B4guKLlbVU.webm&lt;span class="w"&gt; &lt;/span&gt;
ffmpeg&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.4.2-1+b1&lt;span class="w"&gt; &lt;/span&gt;Copyright&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2000&lt;/span&gt;-2018&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;FFmpeg&lt;span class="w"&gt; &lt;/span&gt;developers
&lt;span class="w"&gt;  &lt;/span&gt;built&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Debian&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.3.0-4&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;configuration:&lt;span class="w"&gt; &lt;/span&gt;--prefix&lt;span class="o"&gt;=&lt;/span&gt;/usr&lt;span class="w"&gt; &lt;/span&gt;--extra-version&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;+b1&lt;span class="w"&gt; &lt;/span&gt;--toolchain&lt;span class="o"&gt;=&lt;/span&gt;hardened
&lt;span class="w"&gt; &lt;/span&gt;--libdir&lt;span class="o"&gt;=&lt;/span&gt;/usr/lib/x86_64-linux-gnu&lt;span class="w"&gt; &lt;/span&gt;--incdir&lt;span class="o"&gt;=&lt;/span&gt;/usr/include/x86_64-linux-gnu
&lt;span class="w"&gt; &lt;/span&gt;--enable-gpl&lt;span class="w"&gt; &lt;/span&gt;--disable-stripping&lt;span class="w"&gt; &lt;/span&gt;--enable-avresample&lt;span class="w"&gt; &lt;/span&gt;--enable-avisynth
&lt;span class="w"&gt; &lt;/span&gt;--enable-gnutls&lt;span class="w"&gt; &lt;/span&gt;--enable-ladspa&lt;span class="w"&gt; &lt;/span&gt;--enable-libass&lt;span class="w"&gt; &lt;/span&gt;--enable-libbluray
&lt;span class="w"&gt; &lt;/span&gt;--enable-libbs2b&lt;span class="w"&gt; &lt;/span&gt;--enable-libcaca&lt;span class="w"&gt; &lt;/span&gt;--enable-libcdio&lt;span class="w"&gt; &lt;/span&gt;--enable-libflite
&lt;span class="w"&gt; &lt;/span&gt;--enable-libfontconfig&lt;span class="w"&gt; &lt;/span&gt;--enable-libfreetype&lt;span class="w"&gt; &lt;/span&gt;--enable-libfribidi&lt;span class="w"&gt; &lt;/span&gt;--enable-libgme
&lt;span class="w"&gt; &lt;/span&gt;--enable-libgsm&lt;span class="w"&gt; &lt;/span&gt;--enable-libmp3lame&lt;span class="w"&gt; &lt;/span&gt;--enable-libmysofa&lt;span class="w"&gt; &lt;/span&gt;--enable-libopenjpeg
&lt;span class="w"&gt; &lt;/span&gt;--enable-libopenmpt&lt;span class="w"&gt; &lt;/span&gt;--enable-libopus&lt;span class="w"&gt; &lt;/span&gt;--enable-libpulse&lt;span class="w"&gt; &lt;/span&gt;--enable-librubberband
&lt;span class="w"&gt; &lt;/span&gt;--enable-librsvg&lt;span class="w"&gt; &lt;/span&gt;--enable-libshine&lt;span class="w"&gt; &lt;/span&gt;--enable-libsnappy&lt;span class="w"&gt; &lt;/span&gt;--enable-libsoxr
&lt;span class="w"&gt; &lt;/span&gt;--enable-libspeex&lt;span class="w"&gt; &lt;/span&gt;--enable-libssh&lt;span class="w"&gt; &lt;/span&gt;--enable-libtheora&lt;span class="w"&gt; &lt;/span&gt;--enable-libtwolame
&lt;span class="w"&gt; &lt;/span&gt;--enable-libvorbis&lt;span class="w"&gt; &lt;/span&gt;--enable-libvpx&lt;span class="w"&gt; &lt;/span&gt;--enable-libwavpack&lt;span class="w"&gt; &lt;/span&gt;--enable-libwebp
&lt;span class="w"&gt; &lt;/span&gt;--enable-libx265&lt;span class="w"&gt; &lt;/span&gt;--enable-libxml2&lt;span class="w"&gt; &lt;/span&gt;--enable-libxvid&lt;span class="w"&gt; &lt;/span&gt;--enable-libzmq
&lt;span class="w"&gt; &lt;/span&gt;--enable-libzvbi&lt;span class="w"&gt; &lt;/span&gt;--enable-omx&lt;span class="w"&gt; &lt;/span&gt;--enable-openal&lt;span class="w"&gt; &lt;/span&gt;--enable-opengl&lt;span class="w"&gt; &lt;/span&gt;--enable-sdl2
&lt;span class="w"&gt; &lt;/span&gt;--enable-libdc1394&lt;span class="w"&gt; &lt;/span&gt;--enable-libdrm&lt;span class="w"&gt; &lt;/span&gt;--enable-libiec61883&lt;span class="w"&gt; &lt;/span&gt;--enable-chromaprint
&lt;span class="w"&gt; &lt;/span&gt;--enable-frei0r&lt;span class="w"&gt; &lt;/span&gt;--enable-libopencv&lt;span class="w"&gt; &lt;/span&gt;--enable-libx264&lt;span class="w"&gt; &lt;/span&gt;--enable-shared
&lt;span class="w"&gt;  &lt;/span&gt;libavutil&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;78&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;78&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavcodec&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.107.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.107.100
&lt;span class="w"&gt;  &lt;/span&gt;libavformat&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;83&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;83&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavdevice&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavfilter&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;.107.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;.107.100
&lt;span class="w"&gt;  &lt;/span&gt;libavresample&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;libswscale&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libswresample&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libpostproc&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;54&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;54&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.100
Input&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0, matroska,webm, from &amp;#39;SUPER EUROBEAT MIX-8B4guKLlbVU.webm&amp;#39;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Metadata:
&lt;span class="w"&gt;    &lt;/span&gt;ENCODER&lt;span class="w"&gt;         &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Lavf57.83.100
&lt;span class="w"&gt;  &lt;/span&gt;Duration:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.57,&lt;span class="w"&gt; &lt;/span&gt;start:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.000000,&lt;span class="w"&gt; &lt;/span&gt;bitrate:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;490&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kb/s
&lt;span class="w"&gt;    &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:0(eng): Video: vp9 (Profile 0), yuv420p(tv,&lt;/span&gt;
bt709/unknown/unknown&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;1920x1080,&lt;span class="w"&gt; &lt;/span&gt;SAR&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:1&lt;span class="w"&gt; &lt;/span&gt;DAR&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:9,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;.97&lt;span class="w"&gt; &lt;/span&gt;fps,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;.97&lt;span class="w"&gt; &lt;/span&gt;tbr,&lt;span class="w"&gt; &lt;/span&gt;1k
tbn,&lt;span class="w"&gt; &lt;/span&gt;1k&lt;span class="w"&gt; &lt;/span&gt;tbc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Metadata:
&lt;span class="w"&gt;      &lt;/span&gt;DURATION&lt;span class="w"&gt;        &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.558000000
&lt;span class="w"&gt;    &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:1(eng): Audio: vorbis, 44100 Hz, stereo, fltp (default)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Metadata:
&lt;span class="w"&gt;      &lt;/span&gt;DURATION&lt;span class="w"&gt;        &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.572000000
At&lt;span class="w"&gt; &lt;/span&gt;least&lt;span class="w"&gt; &lt;/span&gt;one&lt;span class="w"&gt; &lt;/span&gt;output&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;must&lt;span class="w"&gt; &lt;/span&gt;be&lt;span class="w"&gt; &lt;/span&gt;specified
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The important line is here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Stream #0:1(eng): Audio: vorbis, 44100 Hz, stereo, fltp (default)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The audio uses the "vorbis" codec. Hence, we should probably use the .ogg
extension for our output file, to ensure we specify a compatible audio
container format. If it were mp3-encoded, we'd use .mp3, and so on.&lt;/p&gt;
&lt;p&gt;Let's extract the audio track from our video file. We need a couple new flags
for &lt;code&gt;ffmpeg&lt;/code&gt;. The first is &lt;code&gt;-vn&lt;/code&gt;, which tells &lt;code&gt;ffmpeg&lt;/code&gt; to not include a video
track. The second is &lt;code&gt;-acodec copy&lt;/code&gt;, which says we want to copy the existing
audio track, rather than re-encode it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;ffmpeg&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;SUPER&lt;span class="se"&gt;\ &lt;/span&gt;EUROBEAT&lt;span class="se"&gt;\ &lt;/span&gt;MIX-8B4guKLlbVU.webm&lt;span class="w"&gt; &lt;/span&gt;-vn&lt;span class="w"&gt; &lt;/span&gt;-acodec&lt;span class="w"&gt; &lt;/span&gt;copy&lt;span class="w"&gt; &lt;/span&gt;super_eurobeat_mix.ogg
ffmpeg&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.4.2-1+b1&lt;span class="w"&gt; &lt;/span&gt;Copyright&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2000&lt;/span&gt;-2018&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;FFmpeg&lt;span class="w"&gt; &lt;/span&gt;developers
&lt;span class="w"&gt;  &lt;/span&gt;built&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Debian&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.3.0-4&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;configuration:&lt;span class="w"&gt; &lt;/span&gt;--prefix&lt;span class="o"&gt;=&lt;/span&gt;/usr&lt;span class="w"&gt; &lt;/span&gt;--extra-version&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;+b1&lt;span class="w"&gt; &lt;/span&gt;--toolchain&lt;span class="o"&gt;=&lt;/span&gt;hardened
&lt;span class="w"&gt; &lt;/span&gt;--libdir&lt;span class="o"&gt;=&lt;/span&gt;/usr/lib/x86_64-linux-gnu&lt;span class="w"&gt; &lt;/span&gt;--incdir&lt;span class="o"&gt;=&lt;/span&gt;/usr/include/x86_64-linux-gnu
&lt;span class="w"&gt; &lt;/span&gt;--enable-gpl&lt;span class="w"&gt; &lt;/span&gt;--disable-stripping&lt;span class="w"&gt; &lt;/span&gt;--enable-avresample&lt;span class="w"&gt; &lt;/span&gt;--enable-avisynth
&lt;span class="w"&gt; &lt;/span&gt;--enable-gnutls&lt;span class="w"&gt; &lt;/span&gt;--enable-ladspa&lt;span class="w"&gt; &lt;/span&gt;--enable-libass&lt;span class="w"&gt; &lt;/span&gt;--enable-libbluray
&lt;span class="w"&gt; &lt;/span&gt;--enable-libbs2b&lt;span class="w"&gt; &lt;/span&gt;--enable-libcaca&lt;span class="w"&gt; &lt;/span&gt;--enable-libcdio&lt;span class="w"&gt; &lt;/span&gt;--enable-libflite
&lt;span class="w"&gt; &lt;/span&gt;--enable-libfontconfig&lt;span class="w"&gt; &lt;/span&gt;--enable-libfreetype&lt;span class="w"&gt; &lt;/span&gt;--enable-libfribidi&lt;span class="w"&gt; &lt;/span&gt;--enable-libgme
&lt;span class="w"&gt; &lt;/span&gt;--enable-libgsm&lt;span class="w"&gt; &lt;/span&gt;--enable-libmp3lame&lt;span class="w"&gt; &lt;/span&gt;--enable-libmysofa&lt;span class="w"&gt; &lt;/span&gt;--enable-libopenjpeg
&lt;span class="w"&gt; &lt;/span&gt;--enable-libopenmpt&lt;span class="w"&gt; &lt;/span&gt;--enable-libopus&lt;span class="w"&gt; &lt;/span&gt;--enable-libpulse&lt;span class="w"&gt; &lt;/span&gt;--enable-librubberband
&lt;span class="w"&gt; &lt;/span&gt;--enable-librsvg&lt;span class="w"&gt; &lt;/span&gt;--enable-libshine&lt;span class="w"&gt; &lt;/span&gt;--enable-libsnappy&lt;span class="w"&gt; &lt;/span&gt;--enable-libsoxr
&lt;span class="w"&gt; &lt;/span&gt;--enable-libspeex&lt;span class="w"&gt; &lt;/span&gt;--enable-libssh&lt;span class="w"&gt; &lt;/span&gt;--enable-libtheora&lt;span class="w"&gt; &lt;/span&gt;--enable-libtwolame
&lt;span class="w"&gt; &lt;/span&gt;--enable-libvorbis&lt;span class="w"&gt; &lt;/span&gt;--enable-libvpx&lt;span class="w"&gt; &lt;/span&gt;--enable-libwavpack&lt;span class="w"&gt; &lt;/span&gt;--enable-libwebp
&lt;span class="w"&gt; &lt;/span&gt;--enable-libx265&lt;span class="w"&gt; &lt;/span&gt;--enable-libxml2&lt;span class="w"&gt; &lt;/span&gt;--enable-libxvid&lt;span class="w"&gt; &lt;/span&gt;--enable-libzmq
&lt;span class="w"&gt; &lt;/span&gt;--enable-libzvbi&lt;span class="w"&gt; &lt;/span&gt;--enable-omx&lt;span class="w"&gt; &lt;/span&gt;--enable-openal&lt;span class="w"&gt; &lt;/span&gt;--enable-opengl&lt;span class="w"&gt; &lt;/span&gt;--enable-sdl2
&lt;span class="w"&gt; &lt;/span&gt;--enable-libdc1394&lt;span class="w"&gt; &lt;/span&gt;--enable-libdrm&lt;span class="w"&gt; &lt;/span&gt;--enable-libiec61883&lt;span class="w"&gt; &lt;/span&gt;--enable-chromaprint
&lt;span class="w"&gt; &lt;/span&gt;--enable-frei0r&lt;span class="w"&gt; &lt;/span&gt;--enable-libopencv&lt;span class="w"&gt; &lt;/span&gt;--enable-libx264&lt;span class="w"&gt; &lt;/span&gt;--enable-shared
&lt;span class="w"&gt;  &lt;/span&gt;libavutil&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;78&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;78&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavcodec&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.107.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.107.100
&lt;span class="w"&gt;  &lt;/span&gt;libavformat&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;83&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;83&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavdevice&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libavfilter&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;.107.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;.107.100
&lt;span class="w"&gt;  &lt;/span&gt;libavresample&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;libswscale&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libswresample&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.100
&lt;span class="w"&gt;  &lt;/span&gt;libpostproc&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;54&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.100&lt;span class="w"&gt; &lt;/span&gt;/&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;54&lt;/span&gt;.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;.100
Input&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0, matroska,webm, from &amp;#39;SUPER EUROBEAT MIX-8B4guKLlbVU.webm&amp;#39;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Metadata:
&lt;span class="w"&gt;    &lt;/span&gt;ENCODER&lt;span class="w"&gt;         &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Lavf57.83.100
&lt;span class="w"&gt;  &lt;/span&gt;Duration:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.57,&lt;span class="w"&gt; &lt;/span&gt;start:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.000000,&lt;span class="w"&gt; &lt;/span&gt;bitrate:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;490&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kb/s
&lt;span class="w"&gt;    &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:0(eng): Video: vp9 (Profile 0), yuv420p(tv,&lt;/span&gt;
bt709/unknown/unknown&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;1920x1080,&lt;span class="w"&gt; &lt;/span&gt;SAR&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:1&lt;span class="w"&gt; &lt;/span&gt;DAR&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:9,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;.97&lt;span class="w"&gt; &lt;/span&gt;fps,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;.97&lt;span class="w"&gt; &lt;/span&gt;tbr,&lt;span class="w"&gt; &lt;/span&gt;1k
tbn,&lt;span class="w"&gt; &lt;/span&gt;1k&lt;span class="w"&gt; &lt;/span&gt;tbc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;default&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Metadata:
&lt;span class="w"&gt;      &lt;/span&gt;DURATION&lt;span class="w"&gt;        &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.558000000
&lt;span class="w"&gt;    &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:1(eng): Audio: vorbis, 44100 Hz, stereo, fltp (default)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Metadata:
&lt;span class="w"&gt;      &lt;/span&gt;DURATION&lt;span class="w"&gt;        &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.572000000
Output&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0, ogg, to &amp;#39;super_eurobeat_mix.ogg&amp;#39;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;Metadata:
&lt;span class="w"&gt;    &lt;/span&gt;encoder&lt;span class="w"&gt;         &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Lavf57.83.100
&lt;span class="w"&gt;    &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:0(eng): Audio: vorbis, 44100 Hz, stereo, fltp (default)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Metadata:
&lt;span class="w"&gt;      &lt;/span&gt;DURATION&lt;span class="w"&gt;        &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.572000000
&lt;span class="w"&gt;      &lt;/span&gt;encoder&lt;span class="w"&gt;         &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;Lavf57.83.100
Stream&lt;span class="w"&gt; &lt;/span&gt;mapping:
&lt;span class="w"&gt;  &lt;/span&gt;Stream&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0:1 -&amp;gt; #0:0 (copy)&lt;/span&gt;
Press&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;q&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;stop,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;?&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;help&lt;/span&gt;
&lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;60863kB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;01&lt;/span&gt;:06:35.54&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bitrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;124&lt;/span&gt;.8kbits/s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;speed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.03e+03x&lt;span class="w"&gt;    &lt;/span&gt;
video:0kB&lt;span class="w"&gt; &lt;/span&gt;audio:60330kB&lt;span class="w"&gt; &lt;/span&gt;subtitle:0kB&lt;span class="w"&gt; &lt;/span&gt;other&lt;span class="w"&gt; &lt;/span&gt;streams:0kB&lt;span class="w"&gt; &lt;/span&gt;global&lt;span class="w"&gt; &lt;/span&gt;headers:4kB
muxing&lt;span class="w"&gt; &lt;/span&gt;overhead:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.884396%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We've successfully extracted &lt;code&gt;super_eurobeat_mix.ogg&lt;/code&gt; from our video file! Go
us!&lt;/p&gt;
&lt;p&gt;Happy listening, and drive safely while you eurobeat. &amp;#x1F3B5;&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Brooklyn.js' Fourth Birthday! November 2017</title><link href="https://hashman.ca/brooklyn-js-4.0/" rel="alternate"></link><published>2017-11-16T00:00:00-05:00</published><updated>2017-11-16T00:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2017-11-16:/brooklyn-js-4.0/</id><summary type="html">&lt;p&gt;I gave a talk for Brooklyn.js' fourth birthday about the state of the Debian Javascript ecosystem &amp;#x1F365;&lt;/p&gt;</summary><content type="html">&lt;p&gt;This year, after being saddened about the state of the Javascript ecosystem in
Debian, I decided to propose a talk to Brooklyn.js to help raise awareness of
some of the problems and solutions, and encourage people to volunteer.&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;First,
  &lt;a href="https://twitter.com/ehashdn?ref_src=twsrc%5Etfw"&gt;@ehashdn&lt;/a&gt;
  is teaching us about the wonders of Debian &amp;amp; answering some questions
  about the peculiarities of node &amp;amp; JavaScript in it 🐧🌀
  &lt;a href="https://t.co/M9KTmxW3aT"&gt;pic.twitter.com/M9KTmxW3aT&lt;/a&gt;
 &lt;/p&gt;
 &amp;mdash; BrooklynJS (@brooklyn_js)
 &lt;a href="https://twitter.com/brooklyn_js/status/931329679264440320?ref_src=twsrc%5Etfw"&gt;November 17, 2017&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;h2&gt;"Why can't we just use /usr/bin/node?!" An introduction to Javascript in Debian&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/brooklynjs/brooklynjs.github.io/issues/442"&gt;Talk description, Brooklyn.js GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/brooklyn-js-4.0/brooklyn_js_debian.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.debian.org"&gt;About Debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://packages.debian.org/sid/nodejs"&gt;nodejs package tracker (unstable)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://packages.debian.org/sid/npm"&gt;npm package tracker (unstable)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Image licensing info&lt;/h3&gt;
&lt;p&gt;"There's no NEW queue for talk slides." &amp;ndash; lamby, Debian Project Leader&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debian logo, copyright 1999 &lt;a href="https://www.debian.org/logos/"&gt;Software in the Public Interest,
  Inc.&lt;/a&gt; used under the &lt;a href="http://creativecommons.org/licenses/by-sa/3.0/"&gt;Attribution-ShareAlike 3.0 Unported
  License&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The image of Tux is attributed to &lt;a href="mailto:lewing@isc.tamu.edu"&gt;Larry Ewing&lt;/a&gt; and &lt;a href="https://www.gimp.org/"&gt;The GIMP&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Debian family tree, authors Andreas Lundqvist, Donjan Rodic, modified by
  &lt;a href="https://commons.wikimedia.org/wiki/User:Michaeldsuarez"&gt;Michaeldsuarez&lt;/a&gt;, used under the &lt;a href="https://www.gnu.org/licenses/fdl-1.3.en.html"&gt;GNU Free Documentation
  License, v1.3&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</content><category term="talks"></category></entry><entry><title>Fun Facts About Email</title><link href="https://hashman.ca/email-tweets/" rel="alternate"></link><published>2017-10-23T00:00:00-04:00</published><updated>2017-10-23T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2017-10-23:/email-tweets/</id><summary type="html">&lt;p&gt;About a month ago, I put together a "1 like = 1 bad fact about email" thread on
Twitter. This got pretty popular and I'm too …&lt;/p&gt;</summary><content type="html">&lt;p&gt;About a month ago, I put together a "1 like = 1 bad fact about email" thread on
Twitter. This got pretty popular and I'm too lazy to turn it into a real blog
post, so here's a link to the thread:&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;
  Okay let&amp;#39;s do this
  &lt;br&gt;
  &lt;br&gt;
  1 like = 1 bad fact about email
 &lt;/p&gt;
 &amp;mdash; e. hashman (@ehashdn)
 &lt;a href="https://twitter.com/ehashdn/status/910514754246017025?ref_src=twsrc%5Etfw"&gt;September 20, 2017&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;</content><category term="blog"></category></entry><entry><title>AnsibleFest 2017 Talk Resources</title><link href="https://hashman.ca/ansiblefest-2017/" rel="alternate"></link><published>2017-09-07T00:00:00-04:00</published><updated>2017-09-07T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2017-09-07:/ansiblefest-2017/</id><summary type="html">&lt;p&gt;Talk resources for "Infrastructure Testing with Molecule", presented at AnsibleFest 2017.&lt;/p&gt;</summary><content type="html">&lt;p&gt;At &lt;a href="https://www.ansible.com/infastructure-testing-with-molecule"&gt;AnsibleFest 2017&lt;/a&gt;, I gave a talk called "Infrastructure Testing with
Molecule". I also presented this talk at our annual Rackspace tech conference,
&lt;a href="https://raxio2017.sched.com/event/CFyk/ansible-infrastructure-testing-with-molecule"&gt;RAX.IO 2017&lt;/a&gt;. Here's some links and resources related to my talk, for
your reference.&lt;/p&gt;
&lt;blockquote class="twitter-tweet tw-align-center" data-lang="en" data-dnt="true"&gt;
 &lt;p lang="en" dir="ltr"&gt;
 .&lt;a href="https://twitter.com/ehashdn?ref_src=twsrc%5Etfw"&gt;@ehashdn&lt;/a&gt; just
 pulled off a live demo of Molecule complete w/ writing expected cowsay output
 and got it right on the first try.
 &lt;a href="https://twitter.com/hashtag/AnsibleFest?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#AnsibleFest&lt;/a&gt;
 &lt;a href="https://t.co/2GFftwei6Y"&gt;pic.twitter.com/2GFftwei6Y&lt;/a&gt;
 &lt;/p&gt;
 &amp;mdash; Lisa Danz (@LisaDanz)
 &lt;a href="https://twitter.com/LisaDanz/status/905912781395730432?ref_src=twsrc%5Etfw"&gt;September
, 2017&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;h2&gt;Infrastructure Testing with Molecule&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ansible.com/infastructure-testing-with-molecule"&gt;Talk video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/ansiblefest-2017/ansiblefest-2017-ehashman.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ehashman/ansiblefest"&gt;Live demo code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://molecule.readthedocs.io/en/stable-1.25/index.html"&gt;Official Molecule documentation&lt;/a&gt;, version 1.25.0&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.ansible.com/ansible/latest/test_strategies.html"&gt;Official Ansible documentation on testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nylas/ansible-test"&gt;ansible-test&lt;/a&gt; by Nylas&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kitchen.ci"&gt;Test Kitchen documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hodgkins.io/testing-ansible-roles-windows-test-kitchen"&gt;Testing Windows Ansible Roles with Test Kitchen&lt;/a&gt;, by Matthew Hodgkins&lt;/li&gt;
&lt;/ul&gt;</content><category term="talks"></category></entry><entry><title>Protect Yo'Self! Jan. 2017 Encryption Workshop Resources</title><link href="https://hashman.ca/protect-yoself/" rel="alternate"></link><published>2017-01-28T00:00:00-05:00</published><updated>2017-01-28T00:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2017-01-28:/protect-yoself/</id><summary type="html">&lt;p&gt;I ran an intro-to-encryption workshop at CodeNewbie's cryptoparty &amp;#x1F510;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Saron Yitbarek of &lt;a href="http://www.codenewbie.org/"&gt;CodeNewbie&lt;/a&gt; hosted a friendly
cryptoparty for beginners called "Protect Yo'Self! A day of workshops on
security and online privacy" that I was thrilled to be able to lead a workshop
at. I wrote a lecture, activities, and curriculum for a section on encryption,
which I led four times in a row from noon to 4PM. Phew!&lt;/p&gt;
&lt;div style="text-align: center"&gt;
  &lt;img alt="A photo of Elana Hashman leading this encryption workshop"
       src="/protect-yoself/crypto_lecture.jpg" /&gt;
  &lt;br /&gt;
  &lt;strong&gt;Candid shot of my lecture, with messaging and network diagrams&lt;/strong&gt;
&lt;/div&gt;

&lt;h2&gt;An Encryption Workshop for Beginners&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.eventbrite.com/e/protect-yoself-a-day-of-workshops-on-security-and-online-privacy-tickets-31114213450#"&gt;EventBrite link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hashman.ca/encryption-workshop/"&gt;Workshop Resources Page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there's enough popular demand, I may work to turn my lecture notes into a
series of blog posts.&lt;/p&gt;</content><category term="talks"></category></entry><entry><title>Brooklyn.js' Third Birthday! November 2016</title><link href="https://hashman.ca/brooklyn-js-3.0/" rel="alternate"></link><published>2016-11-17T00:00:00-05:00</published><updated>2016-11-17T00:00:00-05:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2016-11-17:/brooklyn-js-3.0/</id><summary type="html">&lt;p&gt;I gave a talk for Brooklyn.js' third birthday about ham (amateur) radio &amp;#x1F4FB;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Brian of Brooklyn.js had been bugging me to submit this talk ever since I
gave a rather weak pitch for it in May? of 2016. Eventually, I got around to
&lt;a href="https://github.com/brooklynjs/brooklynjs.github.io/pull/339"&gt;writing up a proposal&lt;/a&gt; and was accepted for the momentous third
birthday of Brooklyn.js! No one warned me that Brendan Eich would be in
attendance...&lt;/p&gt;
&lt;div style="text-align: center"&gt;
  &lt;img alt="Elana Hashman pointing at a K7YAM QSL card, which features a yam"
       src="/brooklyn-js-3.0/qsl.jpg" /&gt;
  &lt;br /&gt;
  &lt;strong&gt;Audience member's photo of a fun QSL card slide&lt;/strong&gt;
&lt;/div&gt;

&lt;h2&gt;AMATEUR RADIO: or, the original world wide indie web&lt;/h2&gt;
&lt;p&gt;Eventually, I will upload the slides and my notes (since the slides are all
pictures and mostly meaningless without context). For now, enjoy the yam.&lt;/p&gt;</content><category term="talks"></category></entry><entry><title>UWaterloo Steam Tunnels</title><link href="https://hashman.ca/tunnels/" rel="alternate"></link><published>2016-10-29T00:00:00-04:00</published><updated>2016-10-29T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2016-10-29:/tunnels/</id><summary type="html">&lt;p&gt;A series of photos from 2014 of the University of Waterloo steam tunnels.&lt;/p&gt;</summary><content type="html">&lt;div style="text-align: center"&gt;
  &lt;img alt="Black and white image down a steam tunnel. A sign says 'WATCH YOUR HEAD - DANGER'."
       src="/images/tunnels/tunnels_00.jpg" /&gt;
  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;A couple years ago I took my camera down with me for a tour of the UWaterloo
steam tunnels.&lt;/p&gt;
&lt;p&gt;The only photos I've ever been able to find online are &lt;a href="http://matt.wandel.ca/tunnels/tunnels.html"&gt;Matt Wandel's,&lt;/a&gt;
but they long predate DSLR technology. While things haven't changed much since
the 1990s, I wondered if people wouldn't appreciate a fresh perspective.&lt;/p&gt;
&lt;p&gt;I am both an amateur photographer and a weird free software zealot who doesn't
understand how to use a Mac or proprietary software in general, so these were
all processed using software called &lt;a href="http://www.darktable.org/"&gt;darktable&lt;/a&gt;, an Adobe Lightroom
clone.&lt;/p&gt;
&lt;p&gt;I assert my copyright on all these photos, but I'm pleased to distribute them
in unwatermarked format for the viewer's enjoyment. If you'd like to request
copies of the higher resolution originals for some reason, please get in touch.&lt;/p&gt;</content><category term="blog"></category></entry><entry><title>Open Source Bridge 2016 Talk Resources</title><link href="https://hashman.ca/osb-2016/" rel="alternate"></link><published>2016-06-21T00:00:00-04:00</published><updated>2016-06-21T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2016-06-21:/osb-2016/</id><summary type="html">&lt;p&gt;Talk resources for "Bringing OOP Best Practices to the World of Functional Programming", presented at Open Source Bridge 2016.&lt;/p&gt;</summary><content type="html">&lt;p&gt;At Open Source Bridge 2016, I gave a talk called &lt;a href="http://opensourcebridge.org/sessions/1817"&gt;Bringing OOP Best Practices
to the World of Functional Programming&lt;/a&gt;. Then I gave a modified
version of this talk for the &lt;a href="http://csclub.uwaterloo.ca/events/MC_4021-2016-10-06-6:00_pm"&gt;University of Waterloo Computer Science
Club&lt;/a&gt; and for the &lt;a href="https://www.meetup.com/Women-Who-Code-DC/events/242932833/"&gt;Lambda Ladies DC chapter&lt;/a&gt;. Here's
some links and resources related to my talk, for your reference.&lt;/p&gt;
&lt;div style="text-align: center"&gt;
  &lt;img alt="A photo of Elana Hashman presenting at Open Source Bridge 2016"
       src="/osb-2016/osb_talk.jpg" /&gt;
  &lt;br /&gt;
  &lt;strong&gt;Candid shot of my presentation at Open Source Bridge 2016&lt;/strong&gt;
&lt;/div&gt;

&lt;h2&gt;Bringing OOP Best Practices to the World of Functional Programming&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://opensourcebridge.org/sessions/1817"&gt;Talk description, Open Source Bridge 2016 website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/osb-2016/osb_2016_ehashman.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/osb-2016/csc_2016_ehashman.pdf"&gt;Talk slides, CSC edition (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/osb-2016/lldc_2017_ehashman.pdf"&gt;Talk slides, Lambda Ladies edition (pdf download)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;&lt;em&gt;Design Patterns&lt;/em&gt; on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.norvig.com/design-patterns/"&gt;"Design Patterns in Dynamic Languages" by Peter Norvig&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;"Meta" UML diagram, Adapter Pattern UML Diagram, Strategy Pattern UML 
diagram are all public domain images.&lt;/p&gt;
&lt;p&gt;The following images were used under the &lt;a href="http://creativecommons.org/licenses/by-sa/3.0/"&gt;Attribution-ShareAlike 3.0 Unported 
License&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UML diagram of composition over inheritance by &lt;a href="https://commons.wikimedia.org/wiki/File:UML_diagram_of_composition_over_inheritance.svg"&gt;Sae1962&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Template Method: UML Class Diagram by &lt;a href="https://commons.wikimedia.org/wiki/File:Template_Method_UML.svg"&gt;Giacomo Ritucci&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Facade Design Pattern in UML by &lt;a href="https://en.wikipedia.org/wiki/File:Example_of_Facade_design_pattern_in_UML.png"&gt;Fuhrmanator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="talks"></category></entry><entry><title>PyCon 2016 Talk Resources</title><link href="https://hashman.ca/pycon-2016/" rel="alternate"></link><published>2016-05-29T00:00:00-04:00</published><updated>2016-05-29T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2016-05-29:/pycon-2016/</id><summary type="html">&lt;p&gt;Talk resources for "Teaching Python: The Hard Parts", presented at PyCon US 2016.&lt;/p&gt;</summary><content type="html">&lt;p&gt;At PyCon 2016, I gave a talk called &lt;a 
href="https://us.pycon.org/2016/schedule/presentation/2012/"&gt;Teaching Python: 
The Hard Parts&lt;/a&gt;. Here's some links and resources related to my talk, for 
your reference.&lt;/p&gt;
&lt;h2&gt;Teaching Python: The Hard Parts&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=CjYEpVNbM-s"&gt;Talk recording, hosted on YouTube&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://us.pycon.org/2016/schedule/presentation/2012/"&gt;Talk description, PyCon 2016 website&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/pycon-2016/pycon_2016_ehashman.pdf"&gt;Talk slides (pdf download)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://wics.uwaterloo.ca/2015/09/pwfb-followup/"&gt;Follow-up PWFB blog post, WiCS UW website&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://wiki.communitydata.cc/Community_Data_Science_Workshops"&gt;Community Data Science Workshops (CDSW), wiki&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://wiki.openhatch.org/Python_Workshops_for_Beginners/Reflections"&gt;Reflections doc, PWFB&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://wiki.communitydata.cc/index.php?search=reflections"&gt;Reflections docs, CDSW&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;iframe style="display: block; margin: auto;" width="560" height="315" src="https://www.youtube-nocookie.com/embed/CjYEpVNbM-s" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;CDSW Photo in talk slides is by &lt;a 
href="http://wiki.communitydata.cc/File:Cdsw_combo_images-1.jpg"&gt;Benjamin Mako 
Hill&lt;/a&gt; and is used under the &lt;a 
href="http://creativecommons.org/licenses/by-sa/3.0/"&gt;Attribution-Share Alike 
3.0 Unported License&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;"Questions?" kitten photo in talk slides is by &lt;a 
href="https://www.flickr.com/photos/lachlanrogers/"&gt;latch.r&lt;/a&gt; and is used 
under the &lt;a 
href="http://creativecommons.org/licenses/by-sa/2.0/"&gt;Attribution-ShareAlike 
2.0 Generic License&lt;/a&gt;.&lt;/p&gt;</content><category term="talks"></category></entry><entry><title>What is a speech without an audience?</title><link href="https://hashman.ca/speech/" rel="alternate"></link><published>2015-06-12T00:00:00-04:00</published><updated>2015-06-12T00:00:00-04:00</updated><author><name>Elana Hashman</name></author><id>tag:hashman.ca,2015-06-12:/speech/</id><summary type="html">&lt;p&gt;Having now officially convocated, I feel comfortable posting what I wrote for 
my valedictory nomination. I was not selected for the honour, but sometimes I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Having now officially convocated, I feel comfortable posting what I wrote for 
my valedictory nomination. I was not selected for the honour, but sometimes I 
like to indulge in a bit of ahistorical fantasy. What would today have been 
like if I had delivered some polished version of this piece?&lt;/p&gt;
&lt;h2&gt;Valedictory Address, Mathematics Class of 2015, First Draft&lt;/h2&gt;
&lt;p&gt;Mr. Chancellor, members of convocation, fellow graduates, and ladies and 
gentlemen... I must say I am ecstatic to be here, as this means I have seen my 
last contour integral, if I have any say in the matter.&lt;/p&gt;
&lt;p&gt;I have the honour to stand before you today and reflect on your future. It is 
so energizing to welcome the threshold of your new and exciting life.&lt;/p&gt;
&lt;p&gt;The University of Waterloo, is, of course, famous for "the spirit of 'Why 
not?'" We are the most innovative university in Canada, for God knows how many 
years in a row now. I suppose it wouldn't be particularly welcome to innovate 
on that trend, so I expect you graduates to keep up the good work. Now, don't 
worry; if you didn't live at Velocity for the past five years, I intend to give 
you a primer right now to ensure the long life of our fine reputation here at 
the University of Waterloo.&lt;/p&gt;
&lt;p&gt;Let's begin with a brief discussion of the properties of the Riemann zeta 
function, despite your voiced objections&amp;mdash;now, I hope you're all familiar 
with this beautiful enigma, and it does spark some interesting conversations. 
For instance, earlier in the term I was speaking with a post-doctorate student 
who was telling me that his calculus students were thoroughly convinced that 
the sum of all the positive integers is -1/12! Now, I'm not sure what branch of 
analysis you subscribe to, but surely you must agree that the sum of all 
positive integers diverges. I can see some of your heads spinning already...
no matter, the flashback to first year calculus will end shortly. So this 
postdoc was telling me his students had told him that their physics professor 
had taught them this result, and if you're not familiar, an analytic 
continuation of the zeta function at the point -1 gives us this curious answer 
of -1/12. Beautiful result from complex analysis. This is useful in making 
string theory and quantum electrodynamics work, among other things.&lt;/p&gt;
&lt;p&gt;So you tell me: which is it? Infinity or -1/12? &lt;strong&gt;[pause]&lt;/strong&gt; I expected a good 
representation of the two answers: both are correct. We know that the zeta 
function evaluated at -1 gives us -1/12, but of course, we also know that the 
implication&amp;mdash;that the sum of all positive integers converges, let alone to 
a negative number&amp;mdash;is absurd. One of them must be wrong! Yet there is deep 
theory that we can use consistently to justify either answer. I can imagine 
those frosh thinking, "I didn't sign up for this!" Maybe you recall a similar 
experience.&lt;/p&gt;
&lt;p&gt;One thing I've noticed in the time I've spent here is that many of us are 
attracted to mathematics for its elegance, its logic, its consistency. 
Sometimes&amp;mdash;and perhaps I romanticize a bit&amp;mdash;but sometimes I feel as 
though in mathematics lies the key to truth. And, then Dr. Kurt Gödel comes 
along, in strict postmodernist style, and softly explains that it is not 
possible for our mathematics to be consistent and complete. It seems that the 
further we advance in our studies of the field, the less certain we can be 
about any truth. We say that Choice is obvious, but then Banach-Tarski devours 
my enthusiasm. Sometimes it feels as though my refuge is a sanatorium.&lt;/p&gt;
&lt;p&gt;You've spent four or five years now collecting knowledge, learning to think 
critically, perfecting your procrastination techniques, cooking on a shoestring 
budget, and kicking yourself over and over again for that STAT midterm. For the 
most part, change in our lives has been gradual, but every so often&amp;mdash;and 
this is something I just adore about mathematics&amp;mdash;there's this burst of 
inspiration, an epiphany, and the answer just clicks into place. Or sometimes, 
you see things so clearly that everything unravels and you realize that you 
can't tie the loose threads back together. Change is frightening.&lt;/p&gt;
&lt;p&gt;These are moments in which danger lies: we may come tantalizingly close to the 
threshold of understanding, but then, out of fear and uncertainty, we back 
away. We lure ourselves into false comfort that mathematics is logical and 
complete and it holds all the answers: and then it strikes us back with 
emptiness and paradox. But this is not confined to math: when I see students on 
this campus faced with issues like discrimination and the challenges of mental 
health, too often do I see my peers justify injustice by arguing it must have 
been deserved. Too often do I watch "The Meritocracy" of STEM held up as 
tautological evidence of its own superiority, while simultaneously watching 
these pundits tear down another classmate's circular proof.  How do you explain 
this contradiction?&lt;/p&gt;
&lt;p&gt;My fellow graduates, I promised you a primer on how to innovate, how to enact 
change. And so I take this these few, precious minutes to focus on this simple, 
uncomfortable concept. Because as we all know, a mathematics degree alone is 
neither necessary nor sufficient for success, but we stand here together to 
tell the world that it matters, that we can think, that we can solve problems. 
I know you can solve problems. So let us tackle the hard ones. Let us embrace 
the cognitive dissonance.&lt;/p&gt;
&lt;p&gt;For the last five years of my life, I have experienced contradiction after 
contradiction that struck me with discomfort, tore my eyes open, spurned me to 
change, spurned me to action. They tell me that Waterloo students are some of 
the most apathetic in the country, but when I watch you persist in your studies 
I know this cannot be further from the truth. You have the fundamentals 
mastered, but I suggest you consider cross-training. I challenge you: let us 
embrace the contradiction inherent in the pursuit of any complete and 
consistent system. The world is waiting for you, and someone is going to ask 
you to choose between infinity and -1/12. And I hope you pick one, and I hope 
you justify it to the fullest of your ability, and I hope that you hold in your 
heart that you are still wrong, and embrace it.&lt;/p&gt;
&lt;p&gt;Thank you.&lt;/p&gt;</content><category term="blog"></category></entry></feed>