Appendix D

Dotfiles

All of Linux configuration lives in plain text files. Your shell aliases, your editor keybindings, your window manager layout, your SSH shortcuts — all of it is a file in your home directory. This is how that works.

Appendix D
Configuration reference
Shell · Git · SSH · Fluxbox

Section 01

What a dotfile is.

A dotfile is any file whose name starts with a dot. That's the entire definition. On Linux, files beginning with . are hidden by default — ls skips them. ls -a shows them. The convention comes from Unix: the developers wanted to hide unimportant files like . (current dir) and .. (parent dir), and the behavior accidentally became the mechanism for hiding all user configuration files.

# Your home directory looks tidy at first glance
ls ~
Desktop Documents Downloads Music Pictures Videos

# -a reveals everything that's actually there
ls -la ~
drwxr-xr-x .config/
-rw-r--r-- .bashrc
-rw-r--r-- .bash_profile
-rw-r--r-- .gitconfig
drwx------ .ssh/
-rw-r--r-- .vimrc
drwxr-xr-x .fluxbox/
drwxr-xr-x Desktop/

Dotfiles are plain text. No binary format, no registry, no app-specific database. You open them in any editor, read them, change them, and the change takes effect immediately (or on next login, depending on the file). This is one of the things that makes Linux configuration so powerful — and so portable. Your entire working environment is just text files.

The old convention was to put config directly in ~/ as ~/.appname or ~/.appnamerc. This works, but after twenty apps it turns your home directory into a mess.

The XDG Base Directory Specification standardized a cleaner approach: config goes in ~/.config/<appname>/, cached data in ~/.cache/, and runtime files in ~/.local/share/. Most modern apps follow this. Older apps (bash, vim, git, ssh) predate it and still use ~/. directly.

You'll see both conventions in the wild. The location doesn't change what the file does — only where it lives. The environment variable $XDG_CONFIG_HOME defaults to ~/.config; some apps let you override it.

# Old-style: directly in home
~/.bashrc
~/.vimrc
~/.gitconfig

# XDG-style: organized under ~/.config/
~/.config/nvim/init.lua
~/.config/i3/config
~/.config/alacritty/alacritty.toml
~/.config/fluxbox/keys

# Check your config dir
ls ~/.config/

Section 02

Shell config: .bashrc, .bash_profile, .profile

Three files, and they're not the same. Bash draws a distinction between a login shell (first session when you log into a machine) and an interactive shell (every terminal you open after that). Login shells read ~/.bash_profile. Interactive shells read ~/.bashrc. In practice, most people just put everything in ~/.bashrc and source it from ~/.bash_profile.

When you first log in — at a TTY, over SSH, or via a display manager — Bash is running as a login shell. It reads /etc/profile (system-wide), then ~/.bash_profile or ~/.profile. This is where you set things that only need to happen once per session: PATH additions, environment variables, auto-starting X.

Every terminal you open afterward is an interactive shell. It reads ~/.bashrc. This is where your aliases, functions, and prompt live — things that should be available in every terminal window.

The standard pattern: put everything useful in ~/.bashrc, and have ~/.bash_profile source it so login shells also get your aliases and prompt.

~/.bash_profile — the standard pattern
# Source .bashrc if it exists
[[ -f ~/.bashrc ]] && . ~/.bashrc

A well-commented .bashrc

Start here. Every item earns its place.

~/.bashrc
# ─── Path ────────────────────────────────────────────────────────
# Add ~/bin to PATH so personal scripts are runnable by name
export PATH="$HOME/bin:$PATH"

# ─── Aliases ─────────────────────────────────────────────────────
# ls with color, one per line, human-readable sizes
alias ls='ls --color=auto'
alias ll='ls -lh --color=auto'
alias la='ls -lah --color=auto'

# Confirm before overwriting
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'

# Navigation shortcuts
alias ..='cd ..'
alias ...='cd ../..'

# Git shortcuts
alias gs='git status'
alias glog="git log --oneline --graph --decorate"

# ─── Prompt ──────────────────────────────────────────────────────
# user@host:~/current/dir $
# \033[01;32m = bold green \033[01;34m = bold blue
PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

# ─── History ─────────────────────────────────────────────────────
# Don't save duplicate lines; ignore commands starting with a space
HISTCONTROL=ignoreboth
HISTSIZE=10000
HISTFILESIZE=20000

# Append to history file rather than overwriting it
shopt -s histappend

Zsh users: ~/.zshrc serves the same role as ~/.bashrc. The syntax for aliases and exports is identical. The prompt variable is PROMPT (or use a prompt theme like starship). There is no ~/.zsh_profile equivalent — zsh uses ~/.zprofile and ~/.zshenv.

Auto-start X from .bash_profile

If you're running a WM setup without a display manager (the approach in Appendix B), this snippet in ~/.bash_profile automatically launches X when you log in on TTY1 — without running a display manager daemon in the background.

~/.bash_profile — auto-start X on TTY1
# Only fire on TTY1, only if X isn't already running
if [[ -z $DISPLAY ]] && [[ $(tty) == /dev/tty1 ]]; then
  exec startx
fi

Log in on TTY2 (Ctrl+Alt+F2) and you still get a plain terminal session. Only TTY1 starts X automatically.

Section 03

Git config: .gitconfig

Git won't let you make a commit without a name and email. That's the minimum. But ~/.gitconfig is also where you set default behavior and create shortcuts that save real time every day.

~/.gitconfig
# ─── Required ────────────────────────────────────────────────────
[user]
  name = Your Name
  email = you@example.com

# ─── Defaults ────────────────────────────────────────────────────
[init]
  defaultBranch = main

[core]
  editor = vim # editor for commit messages
  autocrlf = input # normalize line endings on commit

[pull]
  rebase = false # merge on pull (explicit choice)

[push]
  default = current # push current branch to same-named remote

# ─── Aliases ─────────────────────────────────────────────────────
[alias]
  st = status -sb
  co = checkout
  br = branch -vv
  lg = log --oneline --graph --decorate --all
  last = log -1 HEAD --stat # show last commit
  undo = reset HEAD~1 --mixed # undo last commit, keep changes staged

# ─── Color ───────────────────────────────────────────────────────
[color]
  ui = auto

Test your aliases immediately: git lg shows a compact branching graph of your whole history. git st gives a short status. git last is useful right after a commit to confirm what went in. Once you get used to these you'll wonder how you lived without them.

Section 04

SSH config: ~/.ssh/config

Most people use SSH like this: ssh user@192.168.1.100 -i ~/.ssh/some_key -p 2222. Every. Single. Time. The SSH config file eliminates all of that. You define a named host alias once, and from then on it's just ssh myserver.

The basics — host aliases

Each Host block creates a named shortcut. The Host line is the alias you'll type. Everything indented beneath it is the actual connection parameters.

~/.ssh/config
# A home server on the local network
Host homeserver
  HostName 192.168.1.100
  User mike
  Port 22
# Without the config file
ssh mike@192.168.1.100

# With it
ssh homeserver

Multiple servers, different keys

Each host block is independent. Different servers can use different usernames, ports, and SSH keys — all resolved automatically by the alias you type.

~/.ssh/config
# Work server — uses a dedicated work key
Host work
  HostName work.example.com
  User mcrouse
  Port 22
  IdentityFile ~/.ssh/id_ed25519_work

# Personal VPS — uses a different key, non-standard port
Host vps
  HostName my-vps.example.com
  User mike
  Port 2222
  IdentityFile ~/.ssh/id_ed25519_vps

# Home NAS — key auth, local network
Host nas
  HostName nas.local
  User admin
  IdentityFile ~/.ssh/id_ed25519_nas

Jump hosts (ProxyJump)

A jump host (also called a bastion) is a server that sits on the public internet and tunnels you into a private network behind it. You SSH to the jump host first, then from there to the internal machine. Without the config file, this is two separate SSH commands chained together. With ProxyJump, it's one command — SSH handles the chain automatically.

~/.ssh/config
# The jump host — public-facing, the entry point
Host bastion
  HostName bastion.example.com
  User mike
  IdentityFile ~/.ssh/id_ed25519_bastion

# Internal machine — not reachable directly from outside
Host devbox
  HostName 10.0.0.50 # private IP, only reachable via bastion
  User mike
  ProxyJump bastion # SSH routes through bastion automatically
# One command. SSH connects to bastion, then tunnels to devbox.
ssh devbox

Global defaults with Host *

A Host * block at the end of the file sets defaults that apply to every connection unless overridden by a specific host block above it. SSH reads top to bottom and uses the first matching value it finds — so specific blocks win over the wildcard.

~/.ssh/config — Host * at the end
Host homeserver
  HostName 192.168.1.100
  User mike

# ... other host blocks ...

# Defaults for every connection (must be last)
Host *
  ServerAliveInterval 60 # send keepalive every 60s
  ServerAliveCountMax 3 # drop after 3 missed keepalives
  AddKeysToAgent yes # add key to ssh-agent on first use
  IdentitiesOnly yes # only use keys explicitly listed

ServerAliveInterval prevents the "broken pipe" error you get when a terminal sits idle and the connection silently drops. Without it, you come back to a session after 20 minutes and nothing you type responds — the connection died while you weren't looking. Setting this keeps the connection alive with periodic pings.

SSH config directive reference

Directive What it does Example value
HostName The real address (IP or hostname) to connect to 192.168.1.100 or server.example.com
User Username to log in as mike, admin, root
Port SSH port number (default is 22) 2222
IdentityFile Path to the private key for this host ~/.ssh/id_ed25519_work
ProxyJump Route through another host alias first bastion
LocalForward Forward a local port to a remote address (tunnel) 8080 localhost:8080
ServerAliveInterval Send keepalive every N seconds to prevent dropped connections 60
AddKeysToAgent Automatically add key to ssh-agent on use yes
IdentitiesOnly Only try keys listed in the config, not all keys in the agent yes

Permissions — get these right

SSH is strict about file permissions. If ~/.ssh/config or your private keys are readable by anyone other than you, SSH will refuse to use them. Set these once and forget about them.

~/.ssh/ 700 The directory itself — only you can enter it
~/.ssh/config 600 Config file — read/write for you only
~/.ssh/id_ed25519 600 Private key — read/write for you only, never group or world
~/.ssh/id_ed25519.pub 644 Public key — readable by anyone (that's fine, it's public)
~/.ssh/authorized_keys 600 Server-side — public keys allowed to log in as you
# Fix permissions if something's wrong
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config ~/.ssh/id_*
chmod 644 ~/.ssh/id_*.pub

What NOT to put in ~/.ssh/config: The config file holds connection instructions, not credentials. Never paste private key content into it. Never put passwords. Private keys live as separate files — the IdentityFile directive just points to where they are. The config file itself can be read-only to you, not secret — but treat your private key files as secrets.

Section 05

Fluxbox dotfiles: ~/.fluxbox/

Fluxbox stores its entire configuration in ~/.fluxbox/. No GUI settings panel, no database, no app to open. Three files do most of the work, and all three are plain text you can edit and reload without restarting.

Startup
~/.fluxbox/startup
Shell script that runs when Fluxbox launches. Start tray applets and background services here. Must end with exec fluxbox.
Keybindings
~/.fluxbox/keys
Maps keyboard and mouse shortcuts to Fluxbox commands or shell commands. Changes take effect after right-click → Reconfigure or next login.
Right-click menu
~/.fluxbox/menu
Defines the application menu that appears when you right-click the desktop. Your app launcher. Add, remove, and reorder entries freely.
Session settings
~/.fluxbox/init
Toolbar position, workspace count, slit settings, font choices. Fluxbox writes this file itself — most changes are made through Fluxbox menus, not by hand-editing.

~/.fluxbox/startup

This is a shell script. Each tray applet launches in the background with &, then exec fluxbox at the end hands control to Fluxbox itself. When Fluxbox exits, the X session ends — because exec replaces the shell process rather than spawning a child.

~/.fluxbox/startup
#!/bin/sh

# Enable numlock at startup
numlockx &

# Network manager tray icon
nm-applet &

# Bluetooth (remove on desktops without bluetooth)
blueman-applet &

# Battery icon (remove on desktops)
cbatticon &

# PipeWire volume tray icon
pasystray &

# Set desktop background (fbsetbg -l reuses the last set image)
fbsetbg -l &

# Hand off to Fluxbox — must be last, no &
exec fluxbox

HiDPI scaling — xrandr in startup

On a 4K or 8K display, UI elements are physically tiny unless you scale the logical desktop down. xrandr --scale is how you do this under X11 — it tells Xorg to present a smaller logical canvas that maps onto the full physical panel, making every element appear proportionally larger. --scale 0.5x0.5 halves the logical dimensions: a 4K (3840×2160) panel behaves like a crisp 1920×1080 display.

Step 1 — find your output name

xrandr -q
# Look for lines like:
# DP-1 connected 3840x2160+0+0 (normal left inverted …)
# HDMI-1 connected …
# eDP-1 connected … ← laptop built-in panel
# The output name is everything before "connected"

Step 2 — apply scaling

# 4K display (3840×2160) → logical 1920×1080 (200% / 2× scale)
xrandr --output DP-1 --scale 0.5x0.5

# 8K display (7680×4320) → logical 3840×2160 (200% / 2× scale)
# Same flag; the physical panel is just larger
xrandr --output DP-1 --scale 0.5x0.5

# 8K display → logical 1920×1080 (400% / 4× scale)
xrandr --output DP-1 --scale 0.25x0.25

# Undo scaling (back to native 1:1)
xrandr --output DP-1 --scale 1x1
Display Physical res. --scale flag Logical res. Effective DPI
4K (UHD) 3840×2160 0.5x0.5 1920×1080 ~200% (2× pixels per point)
4K (UHD) 3840×2160 0.667x0.667 2560×1440 ~150% (more screen space)
8K (FUHD) 7680×4320 0.5x0.5 3840×2160 ~200% (4K-equivalent desktop)
8K (FUHD) 7680×4320 0.25x0.25 1920×1080 ~400% (1080p desktop at 8K sharpness)

To make this permanent, add the xrandr call to ~/.fluxbox/startup before the applets and before exec fluxbox. Put it first — some tray applets read DPI on launch, and you want the scaling active before they start.

~/.fluxbox/startup — with HiDPI scaling
#!/bin/sh

# HiDPI scaling — run xrandr -q first to confirm your output name
# 4K at 200% (logical 1920×1080):
xrandr --output DP-1 --scale 0.5x0.5

# Everything below is the same as the minimal startup
numlockx &
nm-applet &
blueman-applet &
cbatticon &
pasystray &
fbsetbg -l &

exec fluxbox

Each connected output gets its own --output flag. Chain them in a single xrandr call so the layout is set atomically — calling it twice can cause a brief flicker.

# 4K primary + 1080p secondary, side by side
xrandr \
  --output DP-1 --scale 0.5x0.5 --pos 0x0 \
  --output HDMI-1 --scale 1x1 --pos 1920x0

# The --pos values are in *logical* pixels after scaling.
# DP-1 at 0.5× occupies logical 1920px wide,
# so HDMI-1 starts at x=1920.

For interactive multi-monitor layout, arandr generates the xrandr command for you — then copy it into startup.

xrandr --scale is a coordinate-transformation hack — X11 has no built-in DPI concept, so scaling is applied after the fact by stretching the framebuffer. It works, but at some cost: the GPU does the downsampling in software, and apps still think they're rendering at 96 DPI unless you also set Xft.dpi.

Wayland compositors handle HiDPI natively. The compositor broadcasts a scale factor to every connected client. Apps that speak Wayland natively (GTK4, Qt6, modern Electron) receive the factor and render at full physical resolution — no interpolation, no framebuffer stretch. Text, icons, and vector graphics come out pixel-perfect. The compositor config is one line per output.

# Sway — ~/.config/sway/config
output DP-1 scale 2

# Hyprland — ~/.config/hypr/hyprland.conf
# format: name, resolution@hz, position, scale
monitor=DP-1,3840x2160@60,0x0,2

# GNOME / KDE Plasma Wayland: Settings → Displays
# Fractional scaling (1.25, 1.5, 1.75) is supported natively

The catch: XWayland. X11 apps running inside a Wayland session go through XWayland, which doesn't see the compositor's scale factor. Those apps still need the old hints. Set them as environment variables (in ~/.profile or your compositor's config) alongside the Wayland scale:

# For X11 apps running under XWayland
export GDK_SCALE=2 # GTK2/GTK3
export QT_SCALE_FACTOR=2 # Qt5
export QT_AUTO_SCREEN_SCALE_FACTOR=0 # disable Qt auto-detection (can conflict)

# Fonts for X11 apps — same Xft.dpi: 192 in ~/.Xresources still applies

Native Wayland apps (GTK4, Qt6, Firefox, Chromium in Wayland mode) pick up the scale factor automatically — no env vars needed. The XWayland workarounds only affect legacy X11 apps that haven't been ported.

~/.fluxbox/keys

Each line is: modifier key :Action or modifier key :ExecCommand program. Mod1 is the Alt key. Mod4 is the Super key (Windows key). The colon before the action is required — it separates the key combination from the Fluxbox command.

~/.fluxbox/keys
# Window cycling — Alt+Tab through open windows on the current workspace
Mod1 Tab :NextWindow {workspace=[current]}
Mod1 Shift Tab :PrevWindow {workspace=[current]}

# Close the focused window — same as clicking the X
Mod1 F4 :Close

# Open the root menu (right-click menu) with a keyboard shortcut
Mod1 z :RootMenu

# Open a terminal with Alt+X — change xterm to your preferred terminal
Mod1 x :ExecCommand xterm

# Screen brightness — requires xbacklight package
XF86MonBrightnessUp :ExecCommand xbacklight -inc 5
XF86MonBrightnessDown :ExecCommand xbacklight -dec 5

# Volume keys using wpctl (PipeWire's control utility)
# wpctl talks directly to PipeWire; amixer talks to ALSA (use one, not both)
XF86AudioLowerVolume :ExecCommand wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
XF86AudioRaiseVolume :ExecCommand wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
XF86AudioMute :ExecCommand wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle

Modifiers: Mod1 = Alt  |  Mod4 = Super (Windows key)  |  Control = Ctrl  |  Shift = Shift

Window actions:

:Close # close focused window
:Minimize # minimize to taskbar
:Maximize # toggle maximize
:NextWindow # cycle to next window
:PrevWindow # cycle to previous window
:NextWorkspace # switch to next workspace
:PrevWorkspace # switch to previous workspace
:RootMenu # open the right-click menu
:ExecCommand <cmd> # run any shell command

After editing keys: right-click desktop → Fluxbox menu → Reconfigure to reload without a full restart.

~/.fluxbox/menu

Right-click anywhere on the desktop and this is what you see. No dock, no application grid — just a menu you define. The format is [type] (Label) {command}. Submenus are nested with [submenu] / [end] blocks.

~/.fluxbox/menu
[begin] (Menu)
  # [exec] runs a shell command when selected
  [exec] (Terminal) {xterm}
  [exec] (Files) {thunar}
  [exec] (Browser) {firefox-esr}
  [exec] (Editor) {gedit}
  [exec] (Display) {arandr}
  [exec] (Audio) {pavucontrol}
  [exec] (Network) {nm-connection-editor}
  # horizontal divider line
  [separator]
  # [submenu] nests a second-level menu
  [submenu] (System)
    [exec] (Reconfigure) {fluxbox-remote reconfigure}
    [restart] (Restart Fluxbox)
    [exit] (Log out)
  [end]
[end]

Edit the menu file, then right-click → System → Reconfigure. Changes appear immediately without restarting Fluxbox. You can add any application, script, or command — if it runs in a terminal, it runs from the menu. See Appendix B for the complete Fluxbox setup guide including PipeWire, tray stack, and APT guardrails.

Section 06

Editor dotfiles

Your editor config is personal. It's also one of the most frequently tweaked dotfiles — small changes add up to a meaningfully different editing experience over time.

~/.vimrc

Vim's config. Even if you only open Vim occasionally, a minimal ~/.vimrc makes it noticeably less abrasive.

~/.vimrc
" Turn off Vi compatibility mode — required for most options to work
set nocompatible

" Line numbers and syntax highlighting
set number
syntax on

" 4-space indentation
set tabstop=4
set shiftwidth=4
set expandtab " use spaces, not literal tabs

" Searching
set incsearch " search as you type
set hlsearch " highlight results
set ignorecase " case-insensitive search...
set smartcase " ...unless you use uppercase

" Show matching brackets
set showmatch

" Keep the cursor 5 lines from the top/bottom when scrolling
set scrolloff=5

~/.config/nvim/ — Neovim

Neovim follows the XDG spec. Configuration lives in ~/.config/nvim/ rather than ~/.vimrc. The main file is either init.vim (Vimscript, compatible with your existing .vimrc) or init.lua (Lua, the modern approach). A plain init.vim that sources your existing ~/.vimrc is a reasonable starting point:

~/.config/nvim/init.vim
" Use existing .vimrc as a base
source ~/.vimrc

Section 07

Other dotfiles worth knowing.

These don't need deep customization to be useful. Knowing they exist means you know where to look when something behaves unexpectedly.

X11
~/.xinitrc
Executed by startx when X launches. On a Fluxbox setup, this contains just exec startfluxbox. On a minimal DE setup, it might start a session manager instead.
X11
~/.Xresources
Per-user X11 resource settings. Controls font, colors, and DPI for X11 apps (including xterm). Applied with xrdb ~/.Xresources at startup — add that line to ~/.fluxbox/startup before exec fluxbox.

On HiDPI displays, pair xrandr --scale with Xft.dpi here so fonts scale correctly too: Xft.dpi: 192 for 200% (standard 96 × 2).
Readline
~/.inputrc
Controls keyboard behavior in any program that uses GNU Readline — bash, python, the psql prompt, etc. Use it to remap keys, enable case-insensitive tab completion, or fix Alt key behavior.
Shell profile
~/.profile
The POSIX sh equivalent of .bash_profile. Read by login shells when .bash_profile doesn't exist, and by some display managers. Good place for environment variables that non-bash shells also need.
Curl
~/.curlrc
Default options for every curl command. Commonly used to set a custom user-agent, enable compressed responses, or silence progress output in scripts.
Less pager
~/.lesskey
Custom keybindings and options for less — the pager used by man pages and git log. Usually not needed until you have a specific annoyance to fix.

xrandr --scale scales the desktop canvas — but fonts and GTK apps read the logical DPI, which stays at 96 unless you tell X11 otherwise. Set Xft.dpi to get text and UI elements to match the visual scale. The standard DPI is 96; double it to 192 for 200% scaling.

~/.Xresources — HiDPI settings
! DPI for font rendering — 96 is standard, 192 is 200% (4K HiDPI)
Xft.dpi: 192

! Sub-pixel rendering (helps on LCD panels; omit on OLED)
Xft.rgba: rgb
Xft.lcdfilter: lcddefault

! Anti-aliasing and hinting
Xft.antialias: 1
Xft.hinting: 1
Xft.hintstyle: hintfull

! xterm: larger font to match 192 DPI
XTerm*faceName: DejaVu Sans Mono
XTerm*faceSize: 11
# Apply immediately (or add to ~/.fluxbox/startup before exec fluxbox)
xrdb -merge ~/.Xresources

# Check that it took
xrdb -query | grep Xft

Scale values: 96 = 100% (standard) · 144 = 150% · 192 = 200% (4K) · 288 = 300% · 384 = 400% (8K at 0.25×)

# Case-insensitive tab completion — the most useful setting
set completion-ignore-case on

# Show completions immediately on first Tab, not second
set show-all-if-ambiguous on

# Color the completion list (highlights matching portion)
set colored-completion-prefix on

# Append / to directory completions
set mark-directories on

These apply to bash tab completion, the Python REPL, psql, and any other program that links against GNU Readline. No restart needed — changes take effect in the next shell you open.

Section 08

Where to start.

Opinion

You don't need to set up all of these at once. Do it incrementally — when something annoys you, fix it with a dotfile. That's how everyone actually builds their config.

Start with ~/.gitconfig. Git refuses to commit without your name and email. Set those first. Then add a lg alias — the branching graph becomes immediately useful and you'll use it constantly.

Then a handful of ~/.bashrc aliases. ll for ls -lh, cp -i and rm -i to protect yourself from accidents, and maybe a shortcut for a directory you visit constantly. That's already a better terminal.

Then ~/.ssh/config once you have more than one server. The first time you have two machines and two keys, typing the full address and -i ~/.ssh/key_name every time becomes tedious fast. Five minutes to set up the config file, and you never type it again.