From e0c771b8b976cee6303a38a4c85eba702dcab460 Mon Sep 17 00:00:00 2001 From: Bayram Tagiev Date: Thu, 8 Jun 2023 11:51:31 +0300 Subject: [PATCH 1/2] tests: updated outdated data Results: TESTS/OK/FAILED 24/24/0 --- tests/results/10 | 33 +- tests/results/11 | 2 - tests/results/12 | 2 - tests/results/15 | 1460 +++++++++++++++++++++++----------------------- tests/results/16 | 6 +- tests/results/17 | 172 +++--- tests/results/18 | 18 +- tests/results/2 | 78 ++- tests/results/21 | 932 ++++++++++++++--------------- tests/results/22 | 932 ++++++++++++++--------------- tests/results/23 | 1 + tests/results/25 | 35 -- tests/results/3 | 18 +- tests/results/4 | 102 ++-- tests/results/5 | 75 +-- tests/results/9 | 33 +- 16 files changed, 1964 insertions(+), 1935 deletions(-) diff --git a/tests/results/10 b/tests/results/10 index a8eca4f0..54d42a50 100644 --- a/tests/results/10 +++ b/tests/results/10 @@ -1,16 +1,23 @@ -# How do I copy a file in Python? +# [`shutil`][1] has many methods you can use. One of which is: #  -# shutil (http://docs.python.org/3/library/shutil.html) has many methods -# you can use. One of which is: - -from shutil import copyfile - -copyfile(src, dst) - -# Copy the contents of the file named src to a file named dst. The -# destination location must be writable; otherwise, an IOError exception -# will be raised. If dst already exists, it will be replaced. Special -# files such as character or block devices and pipes cannot be copied -# with this function. src and dst are path names given as strings. +# ``` +# from shutil import copyfile +# copyfile(src, dst) +# ``` +#  + # - Copy the contents of the file named **src** to a file named +# **dst**. + # - The destination location must be writable; otherwise, an +# **IOError** exception will be raised. + # - If **dst** already exists, it will be replaced. + # - Special files such as character or block devices and pipes cannot +# be copied with this function. + # - With **copy**, **src** and **dst** are path names given as +# __strings__. +#  +# If you use `os.path` operations, use `copy` rather than `copyfile`. +# `copyfile` will only accept strings. +#  + # [1]: http://docs.python.org/3/library/shutil.html #  # [Swati] [so/q/123198] [cc by-sa 3.0] diff --git a/tests/results/11 b/tests/results/11 index d0db3d4e..8b137891 100644 --- a/tests/results/11 +++ b/tests/results/11 @@ -1,3 +1 @@ -from shutil import copyfile -copyfile(src, dst) diff --git a/tests/results/12 b/tests/results/12 index 7c532658..8b137891 100644 --- a/tests/results/12 +++ b/tests/results/12 @@ -1,3 +1 @@ -from shutil import copyfile -copyfile(src, dst) diff --git a/tests/results/15 b/tests/results/15 index ad1f1a9e..c6335a4d 100644 --- a/tests/results/15 +++ b/tests/results/15 @@ -1,383 +1,388 @@ -# Single line comments start with a number symbol. +# Single line comments start with a number symbol. """ Multiline strings can be written  using three "s, and are often used  as documentation. """ -#################################################### -## 1. Primitive Datatypes and Operators -#################################################### - -# You have numbers -3 # => 3 - -# Math is what you would expect -1 + 1 # => 2 -8 - 1 # => 7 -10 * 2 # => 20 -35 / 5 # => 7.0 - -# Integer division rounds down for both positive and negative numbers. -5 // 3 # => 1 --5 // 3 # => -2 -5.0 // 3.0 # => 1.0 # works on floats too --5.0 // 3.0 # => -2.0 - -# The result of division is always a float -10.0 / 3 # => 3.3333333333333335 - -# Modulo operation -7 % 3 # => 1 -# i % j have the same sign as j, unlike C --7 % 3 # => 2 - -# Exponentiation (x**y, x to the yth power) -2**3 # => 8 - -# Enforce precedence with parentheses -1 + 3 * 2 # => 7 -(1 + 3) * 2 # => 8 - -# Boolean values are primitives (Note: the capitalization) -True # => True -False # => False - -# negate with not -not True # => False -not False # => True - -# Boolean Operators -# Note "and" and "or" are case-sensitive -True and False # => False -False or True # => True - -# True and False are actually 1 and 0 but with different keywords -True + True # => 2 -True * 8 # => 8 -False - 5 # => -5 - -# Comparison operators look at the numerical value of True and False -0 == False # => True -1 == True # => True -2 == True # => False --5 != False # => True - -# Using boolean logical operators on ints casts them to booleans for evaluation, but their non-cast value is returned -# Don't mix up with bool(ints) and bitwise and/or (&,|) -bool(0) # => False -bool(4) # => True -bool(-6) # => True -0 and 2 # => 0 --5 or 0 # => -5 - -# Equality is == -1 == 1 # => True -2 == 1 # => False - -# Inequality is != -1 != 1 # => False -2 != 1 # => True - -# More comparisons -1 < 10 # => True -1 > 10 # => False -2 <= 2 # => True -2 >= 2 # => True - -# Seeing whether a value is in a range -1 < 2 and 2 < 3 # => True -2 < 3 and 3 < 2 # => False -# Chaining makes this look nicer -1 < 2 < 3 # => True -2 < 3 < 2 # => False - -# (is vs. ==) is checks if two variables refer to the same object, but == checks -# if the objects pointed to have the same values. -a = [1, 2, 3, 4] # Point a at a new list, [1, 2, 3, 4] -b = a # Point b at what a is pointing to -b is a # => True, a and b refer to the same object -b == a # => True, a's and b's objects are equal -b = [1, 2, 3, 4] # Point b at a new list, [1, 2, 3, 4] -b is a # => False, a and b do not refer to the same object -b == a # => True, a's and b's objects are equal - -# Strings are created with " or ' +#################################################### +## 1. Primitive Datatypes and Operators +#################################################### + +# You have numbers +3 # => 3 + +# Math is what you would expect +1 + 1 # => 2 +8 - 1 # => 7 +10 * 2 # => 20 +35 / 5 # => 7.0 + +# Integer division rounds down for both positive and negative numbers. +5 // 3 # => 1 +-5 // 3 # => -2 +5.0 // 3.0 # => 1.0 # works on floats too +-5.0 // 3.0 # => -2.0 + +# The result of division is always a float +10.0 / 3 # => 3.3333333333333335 + +# Modulo operation +7 % 3 # => 1 +# i % j have the same sign as j, unlike C +-7 % 3 # => 2 + +# Exponentiation (x**y, x to the yth power) +2**3 # => 8 + +# Enforce precedence with parentheses +1 + 3 * 2 # => 7 +(1 + 3) * 2 # => 8 + +# Boolean values are primitives (Note: the capitalization) +True # => True +False # => False + +# negate with not +not True # => False +not False # => True + +# Boolean Operators +# Note "and" and "or" are case-sensitive +True and False # => False +False or True # => True + +# True and False are actually 1 and 0 but with different keywords +True + True # => 2 +True * 8 # => 8 +False - 5 # => -5 + +# Comparison operators look at the numerical value of True and False +0 == False # => True +2 > True # => True +2 == True # => False +-5 != False # => True + +# None, 0, and empty strings/lists/dicts/tuples/sets all evaluate to False. +# All other values are True +bool(0) # => False +bool("") # => False +bool([]) # => False +bool({}) # => False +bool(()) # => False +bool(set()) # => False +bool(4) # => True +bool(-6) # => True + +# Using boolean logical operators on ints casts them to booleans for evaluation, +# but their non-cast value is returned. Don't mix up with bool(ints) and bitwise +# and/or (&,|) +bool(0) # => False +bool(2) # => True +0 and 2 # => 0 +bool(-5) # => True +bool(2) # => True +-5 or 0 # => -5 + +# Equality is == +1 == 1 # => True +2 == 1 # => False + +# Inequality is != +1 != 1 # => False +2 != 1 # => True + +# More comparisons +1 < 10 # => True +1 > 10 # => False +2 <= 2 # => True +2 >= 2 # => True + +# Seeing whether a value is in a range +1 < 2 and 2 < 3 # => True +2 < 3 and 3 < 2 # => False +# Chaining makes this look nicer +1 < 2 < 3 # => True +2 < 3 < 2 # => False + +# (is vs. ==) is checks if two variables refer to the same object, but == checks +# if the objects pointed to have the same values. +a = [1, 2, 3, 4] # Point a at a new list, [1, 2, 3, 4] +b = a # Point b at what a is pointing to +b is a # => True, a and b refer to the same object +b == a # => True, a's and b's objects are equal +b = [1, 2, 3, 4] # Point b at a new list, [1, 2, 3, 4] +b is a # => False, a and b do not refer to the same object +b == a # => True, a's and b's objects are equal + +# Strings are created with " or ' "This is a string." 'This is also a string.' -# Strings can be added too -"Hello " + "world!" # => "Hello world!" -# String literals (but not variables) can be concatenated without using '+' -"Hello " "world!" # => "Hello world!" +# Strings can be added too +"Hello " + "world!" # => "Hello world!" +# String literals (but not variables) can be concatenated without using '+' +"Hello " "world!" # => "Hello world!" -# A string can be treated like a list of characters -"Hello world!"[0] # => 'H' +# A string can be treated like a list of characters +"Hello world!"[0] # => 'H' -# You can find the length of a string -len("This is a string") # => 16 +# You can find the length of a string +len("This is a string") # => 16 -# You can also format using f-strings or formatted string literals (in Python 3.6+) +# Since Python 3.6, you can use f-strings or formatted string literals. name = "Reiko" -f"She said her name is {name}." # => "She said her name is Reiko" -# You can basically put any Python expression inside the braces and it will be output in the string. -f"{name} is {len(name)} characters long." # => "Reiko is 5 characters long." - -# None is an object -None # => None - -# Don't use the equality "==" symbol to compare objects to None -# Use "is" instead. This checks for equality of object identity. -"etc" is None # => False -None is None # => True - -# None, 0, and empty strings/lists/dicts/tuples all evaluate to False. -# All other values are True -bool(0) # => False -bool("") # => False -bool([]) # => False -bool({}) # => False -bool(()) # => False - -#################################################### -## 2. Variables and Collections -#################################################### - -# Python has a print function -print("I'm Python. Nice to meet you!") # => I'm Python. Nice to meet you! - -# By default the print function also prints out a newline at the end. -# Use the optional argument end to change the end string. -print("Hello, World", end="!") # => Hello, World! - -# Simple way to get input data from console -input_string_var = input("Enter some data: ") # Returns the data as a string - -# There are no declarations, only assignments. -# Convention is to use lower_case_with_underscores -some_var = 5 -some_var # => 5 - -# Accessing a previously unassigned variable is an exception. -# See Control Flow to learn more about exception handling. -some_unknown_var # Raises a NameError - -# if can be used as an expression -# Equivalent of C's '?:' ternary operator -"yay!" if 0 > 1 else "nay!" # => "nay!" - -# Lists store sequences +f"She said her name is {name}." # => "She said her name is Reiko" +# Any valid Python expression inside these braces is returned to the string. +f"{name} is {len(name)} characters long." # => "Reiko is 5 characters long." + +# None is an object +None # => None + +# Don't use the equality "==" symbol to compare objects to None +# Use "is" instead. This checks for equality of object identity. +"etc" is None # => False +None is None # => True + +#################################################### +## 2. Variables and Collections +#################################################### + +# Python has a print function +print("I'm Python. Nice to meet you!") # => I'm Python. Nice to meet you! + +# By default the print function also prints out a newline at the end. +# Use the optional argument end to change the end string. +print("Hello, World", end="!") # => Hello, World! + +# Simple way to get input data from console +input_string_var = input("Enter some data: ") # Returns the data as a string + +# There are no declarations, only assignments. +# Convention is to use lower_case_with_underscores +some_var = 5 +some_var # => 5 + +# Accessing a previously unassigned variable is an exception. +# See Control Flow to learn more about exception handling. +some_unknown_var # Raises a NameError + +# if can be used as an expression +# Equivalent of C's '?:' ternary operator +"yay!" if 0 > 1 else "nay!" # => "nay!" + +# Lists store sequences li = [] -# You can start with a prefilled list -other_li = [4, 5, 6] - -# Add stuff to the end of a list with append -li.append(1) # li is now [1] -li.append(2) # li is now [1, 2] -li.append(4) # li is now [1, 2, 4] -li.append(3) # li is now [1, 2, 4, 3] -# Remove from the end with pop -li.pop() # => 3 and li is now [1, 2, 4] -# Let's put it back -li.append(3) # li is now [1, 2, 4, 3] again. - -# Access a list like you would any array -li[0] # => 1 -# Look at the last element -li[-1] # => 3 - -# Looking out of bounds is an IndexError -li[4] # Raises an IndexError - -# You can look at ranges with slice syntax. -# The start index is included, the end index is not -# (It's a closed/open range for you mathy types.) -li[1:3] # Return list from index 1 to 3 => [2, 4] -li[2:] # Return list starting from index 2 => [4, 3] -li[:3] # Return list from beginning until index 3 => [1, 2, 4] -li[::2] # Return list selecting every second entry => [1, 4] -li[::-1] # Return list in reverse order => [3, 4, 2, 1] -# Use any combination of these to make advanced slices -# li[start:end:step] - -# Make a one layer deep copy using slices -li2 = li[:] # => li2 = [1, 2, 4, 3] but (li2 is li) will result in false. - -# Remove arbitrary elements from a list with "del" -del li[2] # li is now [1, 2, 3] - -# Remove first occurrence of a value -li.remove(2) # li is now [1, 3] -li.remove(2) # Raises a ValueError as 2 is not in the list - -# Insert an element at a specific index -li.insert(1, 2) # li is now [1, 2, 3] again - -# Get the index of the first item found matching the argument -li.index(2) # => 1 -li.index(4) # Raises a ValueError as 4 is not in the list - -# You can add lists -# Note: values for li and for other_li are not modified. -li + other_li # => [1, 2, 3, 4, 5, 6] - -# Concatenate lists with "extend()" -li.extend(other_li) # Now li is [1, 2, 3, 4, 5, 6] - -# Check for existence in a list with "in" -1 in li # => True - -# Examine the length with "len()" -len(li) # => 6 - - -# Tuples are like lists but are immutable. -tup = (1, 2, 3) -tup[0] # => 1 -tup[0] = 3 # Raises a TypeError - -# Note that a tuple of length one has to have a comma after the last element but -# tuples of other lengths, even zero, do not. -type((1)) # =>  -type((1,)) # =>  -type(()) # =>  - -# You can do most of the list operations on tuples too -len(tup) # => 3 -tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) -tup[:2] # => (1, 2) -2 in tup # => True - -# You can unpack tuples (or lists) into variables -a, b, c = (1, 2, 3) # a is now 1, b is now 2 and c is now 3 -# You can also do extended unpacking -a, *b, c = (1, 2, 3, 4) # a is now 1, b is now [2, 3] and c is now 4 -# Tuples are created by default if you leave out the parentheses -d, e, f = 4, 5, 6 # tuple 4, 5, 6 is unpacked into variables d, e and f -# respectively such that d = 4, e = 5 and f = 6 -# Now look how easy it is to swap two values -e, d = d, e # d is now 5 and e is now 4 - - -# Dictionaries store mappings from keys to values +# You can start with a prefilled list +other_li = [4, 5, 6] + +# Add stuff to the end of a list with append +li.append(1) # li is now [1] +li.append(2) # li is now [1, 2] +li.append(4) # li is now [1, 2, 4] +li.append(3) # li is now [1, 2, 4, 3] +# Remove from the end with pop +li.pop() # => 3 and li is now [1, 2, 4] +# Let's put it back +li.append(3) # li is now [1, 2, 4, 3] again. + +# Access a list like you would any array +li[0] # => 1 +# Look at the last element +li[-1] # => 3 + +# Looking out of bounds is an IndexError +li[4] # Raises an IndexError + +# You can look at ranges with slice syntax. +# The start index is included, the end index is not +# (It's a closed/open range for you mathy types.) +li[1:3] # Return list from index 1 to 3 => [2, 4] +li[2:] # Return list starting from index 2 => [4, 3] +li[:3] # Return list from beginning until index 3 => [1, 2, 4] +li[::2] # Return list selecting every second entry => [1, 4] +li[::-1] # Return list in reverse order => [3, 4, 2, 1] +# Use any combination of these to make advanced slices +# li[start:end:step] + +# Make a one layer deep copy using slices +li2 = li[:] # => li2 = [1, 2, 4, 3] but (li2 is li) will result in false. + +# Remove arbitrary elements from a list with "del" +del li[2] # li is now [1, 2, 3] + +# Remove first occurrence of a value +li.remove(2) # li is now [1, 3] +li.remove(2) # Raises a ValueError as 2 is not in the list + +# Insert an element at a specific index +li.insert(1, 2) # li is now [1, 2, 3] again + +# Get the index of the first item found matching the argument +li.index(2) # => 1 +li.index(4) # Raises a ValueError as 4 is not in the list + +# You can add lists +# Note: values for li and for other_li are not modified. +li + other_li # => [1, 2, 3, 4, 5, 6] + +# Concatenate lists with "extend()" +li.extend(other_li) # Now li is [1, 2, 3, 4, 5, 6] + +# Check for existence in a list with "in" +1 in li # => True + +# Examine the length with "len()" +len(li) # => 6 + + +# Tuples are like lists but are immutable. +tup = (1, 2, 3) +tup[0] # => 1 +tup[0] = 3 # Raises a TypeError + +# Note that a tuple of length one has to have a comma after the last element but +# tuples of other lengths, even zero, do not. +type((1)) # =>  +type((1,)) # =>  +type(()) # =>  + +# You can do most of the list operations on tuples too +len(tup) # => 3 +tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) +tup[:2] # => (1, 2) +2 in tup # => True + +# You can unpack tuples (or lists) into variables +a, b, c = (1, 2, 3) # a is now 1, b is now 2 and c is now 3 +# You can also do extended unpacking +a, *b, c = (1, 2, 3, 4) # a is now 1, b is now [2, 3] and c is now 4 +# Tuples are created by default if you leave out the parentheses +d, e, f = 4, 5, 6 # tuple 4, 5, 6 is unpacked into variables d, e and f +# respectively such that d = 4, e = 5 and f = 6 +# Now look how easy it is to swap two values +e, d = d, e # d is now 5 and e is now 4 + + +# Dictionaries store mappings from keys to values empty_dict = {} -# Here is a prefilled dictionary -filled_dict = {"one": 1, "two": 2, "three": 3} +# Here is a prefilled dictionary +filled_dict = {"one": 1, "two": 2, "three": 3} -# Note keys for dictionaries have to be immutable types. This is to ensure that -# the key can be converted to a constant hash value for quick look-ups. -# Immutable types include ints, floats, strings, tuples. -invalid_dict = {[1,2,3]: "123"} # => Raises a TypeError: unhashable type: 'list' -valid_dict = {(1,2,3):[1,2,3]} # Values can be of any type, however. +# Note keys for dictionaries have to be immutable types. This is to ensure that +# the key can be converted to a constant hash value for quick look-ups. +# Immutable types include ints, floats, strings, tuples. +invalid_dict = {[1,2,3]: "123"} # => Yield a TypeError: unhashable type: 'list' +valid_dict = {(1,2,3):[1,2,3]} # Values can be of any type, however. -# Look up values with [] -filled_dict["one"] # => 1 +# Look up values with [] +filled_dict["one"] # => 1 -# Get all keys as an iterable with "keys()". We need to wrap the call in list() -# to turn it into a list. We'll talk about those later. Note - for Python -# versions <3.7, dictionary key ordering is not guaranteed. Your results might -# not match the example below exactly. However, as of Python 3.7, dictionary -# items maintain the order at which they are inserted into the dictionary. -list(filled_dict.keys()) # => ["three", "two", "one"] in Python <3.7 -list(filled_dict.keys()) # => ["one", "two", "three"] in Python 3.7+ +# Get all keys as an iterable with "keys()". We need to wrap the call in list() +# to turn it into a list. We'll talk about those later. Note - for Python +# versions <3.7, dictionary key ordering is not guaranteed. Your results might +# not match the example below exactly. However, as of Python 3.7, dictionary +# items maintain the order at which they are inserted into the dictionary. +list(filled_dict.keys()) # => ["three", "two", "one"] in Python <3.7 +list(filled_dict.keys()) # => ["one", "two", "three"] in Python 3.7+ -# Get all values as an iterable with "values()". Once again we need to wrap it -# in list() to get it out of the iterable. Note - Same as above regarding key -# ordering. -list(filled_dict.values()) # => [3, 2, 1] in Python <3.7 -list(filled_dict.values()) # => [1, 2, 3] in Python 3.7+ +# Get all values as an iterable with "values()". Once again we need to wrap it +# in list() to get it out of the iterable. Note - Same as above regarding key +# ordering. +list(filled_dict.values()) # => [3, 2, 1] in Python <3.7 +list(filled_dict.values()) # => [1, 2, 3] in Python 3.7+ -# Check for existence of keys in a dictionary with "in" -"one" in filled_dict # => True -1 in filled_dict # => False +# Check for existence of keys in a dictionary with "in" +"one" in filled_dict # => True +1 in filled_dict # => False -# Looking up a non-existing key is a KeyError -filled_dict["four"] # KeyError +# Looking up a non-existing key is a KeyError +filled_dict["four"] # KeyError -# Use "get()" method to avoid the KeyError -filled_dict.get("one") # => 1 -filled_dict.get("four") # => None -# The get method supports a default argument when the value is missing -filled_dict.get("one", 4) # => 1 -filled_dict.get("four", 4) # => 4 +# Use "get()" method to avoid the KeyError +filled_dict.get("one") # => 1 +filled_dict.get("four") # => None +# The get method supports a default argument when the value is missing +filled_dict.get("one", 4) # => 1 +filled_dict.get("four", 4) # => 4 -# "setdefault()" inserts into a dictionary only if the given key isn't present -filled_dict.setdefault("five", 5) # filled_dict["five"] is set to 5 -filled_dict.setdefault("five", 6) # filled_dict["five"] is still 5 +# "setdefault()" inserts into a dictionary only if the given key isn't present +filled_dict.setdefault("five", 5) # filled_dict["five"] is set to 5 +filled_dict.setdefault("five", 6) # filled_dict["five"] is still 5 -# Adding to a dictionary -filled_dict.update({"four":4}) # => {"one": 1, "two": 2, "three": 3, "four": 4} -filled_dict["four"] = 4 # another way to add to dict +# Adding to a dictionary +filled_dict.update({"four":4}) # => {"one": 1, "two": 2, "three": 3, "four": 4} +filled_dict["four"] = 4 # another way to add to dict -# Remove keys from a dictionary with del -del filled_dict["one"] # Removes the key "one" from filled dict +# Remove keys from a dictionary with del +del filled_dict["one"] # Removes the key "one" from filled dict -# From Python 3.5 you can also use the additional unpacking options -{'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2} -{'a': 1, **{'a': 2}} # => {'a': 2} +# From Python 3.5 you can also use the additional unpacking options +{'a': 1, **{'b': 2}} # => {'a': 1, 'b': 2} +{'a': 1, **{'a': 2}} # => {'a': 2} -# Sets store ... well sets -empty_set = set() -# Initialize a set with a bunch of values. Yeah, it looks a bit like a dict. Sorry. -some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4} +# Sets store ... well sets +empty_set = set() +# Initialize a set with a bunch of values. +some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4} -# Similar to keys of a dictionary, elements of a set have to be immutable. -invalid_set = {[1], 1} # => Raises a TypeError: unhashable type: 'list' -valid_set = {(1,), 1} +# Similar to keys of a dictionary, elements of a set have to be immutable. +invalid_set = {[1], 1} # => Raises a TypeError: unhashable type: 'list' +valid_set = {(1,), 1} -# Add one more item to the set +# Add one more item to the set filled_set = some_set -filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5} -# Sets do not have duplicate elements -filled_set.add(5) # it remains as before {1, 2, 3, 4, 5} +filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5} +# Sets do not have duplicate elements +filled_set.add(5) # it remains as before {1, 2, 3, 4, 5} -# Do set intersection with & -other_set = {3, 4, 5, 6} -filled_set & other_set # => {3, 4, 5} +# Do set intersection with & +other_set = {3, 4, 5, 6} +filled_set & other_set # => {3, 4, 5} -# Do set union with | -filled_set | other_set # => {1, 2, 3, 4, 5, 6} +# Do set union with | +filled_set | other_set # => {1, 2, 3, 4, 5, 6} -# Do set difference with - -{1, 2, 3, 4} - {2, 3, 5} # => {1, 4} +# Do set difference with - +{1, 2, 3, 4} - {2, 3, 5} # => {1, 4} -# Do set symmetric difference with ^ -{1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} +# Do set symmetric difference with ^ +{1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5} -# Check if set on the left is a superset of set on the right -{1, 2} >= {1, 2, 3} # => False +# Check if set on the left is a superset of set on the right +{1, 2} >= {1, 2, 3} # => False -# Check if set on the left is a subset of set on the right -{1, 2} <= {1, 2, 3} # => True +# Check if set on the left is a subset of set on the right +{1, 2} <= {1, 2, 3} # => True -# Check for existence in a set with in -2 in filled_set # => True -10 in filled_set # => False +# Check for existence in a set with in +2 in filled_set # => True +10 in filled_set # => False -# Make a one layer deep copy -filled_set = some_set.copy() # filled_set is {1, 2, 3, 4, 5} -filled_set is some_set # => False +# Make a one layer deep copy +filled_set = some_set.copy() # filled_set is {1, 2, 3, 4, 5} +filled_set is some_set # => False -#################################################### -## 3. Control Flow and Iterables -#################################################### +#################################################### +## 3. Control Flow and Iterables +#################################################### -# Let's just make a variable -some_var = 5 +# Let's just make a variable +some_var = 5 -# Here is an if statement. Indentation is significant in Python! -# Convention is to use four spaces, not tabs. -# This prints "some_var is smaller than 10" -if some_var > 10: - print("some_var is totally bigger than 10.") -elif some_var < 10: # This elif clause is optional. - print("some_var is smaller than 10.") -else: # This is optional too. - print("some_var is indeed 10.") +# Here is an if statement. Indentation is significant in Python! +# Convention is to use four spaces, not tabs. +# This prints "some_var is smaller than 10" +if some_var > 10: + print("some_var is totally bigger than 10.") +elif some_var < 10: # This elif clause is optional. + print("some_var is smaller than 10.") +else: # This is optional too. + print("some_var is indeed 10.") """ @@ -388,20 +393,20 @@  mouse is a mammal """ for animal in ["dog", "cat", "mouse"]: - # You can use format() to interpolate formatted strings - print("{} is a mammal".format(animal)) + # You can use format() to interpolate formatted strings + print("{} is a mammal".format(animal)) """ "range(number)" returns an iterable of numbers -from zero to the given number +from zero up to (but excluding) the given number prints:  0  1  2  3 """ -for i in range(4): - print(i) +for i in range(4): + print(i) """ "range(lower, upper)" returns an iterable of numbers @@ -412,8 +417,8 @@  6  7 """ -for i in range(4, 8): - print(i) +for i in range(4, 8): + print(i) """ "range(lower, upper, step)" returns an iterable of numbers @@ -423,19 +428,18 @@  4  6 """ -for i in range(4, 8, 2): - print(i) +for i in range(4, 8, 2): + print(i) """ -To loop over a list, and retrieve both the index and the value of each item in the list -prints: +Loop over a list to retrieve both the index and the value of each list item:  0 dog  1 cat  2 mouse """ animals = ["dog", "cat", "mouse"] -for i, value in enumerate(animals): - print(i, value) +for i, value in enumerate(animals): + print(i, value) """ While loops go until a condition is no longer met. @@ -445,544 +449,556 @@  2  3 """ -x = 0 -while x < 4: - print(x) - x += 1 # Shorthand for x = x + 1 +x = 0 +while x < 4: + print(x) + x += 1 # Shorthand for x = x + 1 -# Handle exceptions with a try/except block +# Handle exceptions with a try/except block try: - # Use "raise" to raise an error + # Use "raise" to raise an error  raise IndexError("This is an index error") except IndexError as e: - pass # Pass is just a no-op. Usually you would do recovery here. + pass # Refrain from this, provide a recovery (next example). except (TypeError, NameError): - pass # Multiple exceptions can be handled together, if required. -else: # Optional clause to the try/except block. Must follow all except blocks - print("All good!") # Runs only if the code in try raises no exceptions -finally: # Execute under all circumstances - print("We can clean up resources here") - -# Instead of try/finally to cleanup resources you can use a with statement -with open("myfile.txt") as f: + pass # Multiple exceptions can be processed jointly. +else: # Optional clause to the try/except block. Must follow + # all except blocks. + print("All good!") # Runs only if the code in try raises no exceptions +finally: # Execute under all circumstances + print("We can clean up resources here") + +# Instead of try/finally to cleanup resources you can use a with statement +with open("myfile.txt") as f:  for line in f: - print(line) + print(line) -# Writing to a file -contents = {"aa": 12, "bb": 21} -with open("myfile1.txt", "w+") as file: - file.write(str(contents)) # writes a string to a file +# Writing to a file +contents = {"aa": 12, "bb": 21} +with open("myfile1.txt", "w+") as file: + file.write(str(contents)) # writes a string to a file -with open("myfile2.txt", "w+") as file: - file.write(json.dumps(contents)) # writes an object to a file +import json +with open("myfile2.txt", "w+") as file: + file.write(json.dumps(contents)) # writes an object to a file -# Reading from a file -with open('myfile1.txt', "r+") as file: - contents = file.read() # reads a string from a file -print(contents) -# print: {"aa": 12, "bb": 21} +# Reading from a file +with open('myfile1.txt', "r+") as file: + contents = file.read() # reads a string from a file +print(contents) +# print: {"aa": 12, "bb": 21} -with open('myfile2.txt', "r+") as file: - contents = json.load(file) # reads a json object from a file -print(contents) -# print: {"aa": 12, "bb": 21} +with open('myfile2.txt', "r+") as file: + contents = json.load(file) # reads a json object from a file +print(contents) +# print: {"aa": 12, "bb": 21} -# Python offers a fundamental abstraction called the Iterable. -# An iterable is an object that can be treated as a sequence. -# The object returned by the range function, is an iterable. +# Python offers a fundamental abstraction called the Iterable. +# An iterable is an object that can be treated as a sequence. +# The object returned by the range function, is an iterable. -filled_dict = {"one": 1, "two": 2, "three": 3} +filled_dict = {"one": 1, "two": 2, "three": 3} our_iterable = filled_dict.keys() -print(our_iterable) # => dict_keys(['one', 'two', 'three']). This is an object that implements our Iterable interface. +print(our_iterable) # => dict_keys(['one', 'two', 'three']). This is an object + # that implements our Iterable interface. -# We can loop over it. +# We can loop over it. for i in our_iterable: - print(i) # Prints one, two, three + print(i) # Prints one, two, three -# However we cannot address elements by index. -our_iterable[1] # Raises a TypeError +# However we cannot address elements by index. +our_iterable[1] # Raises a TypeError -# An iterable is an object that knows how to create an iterator. -our_iterator = iter(our_iterable) +# An iterable is an object that knows how to create an iterator. +our_iterator = iter(our_iterable) -# Our iterator is an object that can remember the state as we traverse through it. -# We get the next object with "next()". -next(our_iterator) # => "one" +# Our iterator is an object that can remember the state as we traverse through +# it. We get the next object with "next()". +next(our_iterator) # => "one" -# It maintains state as we iterate. -next(our_iterator) # => "two" -next(our_iterator) # => "three" +# It maintains state as we iterate. +next(our_iterator) # => "two" +next(our_iterator) # => "three" -# After the iterator has returned all of its data, it raises a StopIteration exception -next(our_iterator) # Raises StopIteration +# After the iterator has returned all of its data, it raises a +# StopIteration exception +next(our_iterator) # Raises StopIteration -# We can also loop over it, in fact, "for" does this implicitly! -our_iterator = iter(our_iterable) +# We can also loop over it, in fact, "for" does this implicitly! +our_iterator = iter(our_iterable) for i in our_iterator: - print(i) # Prints one, two, three + print(i) # Prints one, two, three -# You can grab all the elements of an iterable or iterator by calling list() on it. -list(our_iterable) # => Returns ["one", "two", "three"] -list(our_iterator) # => Returns [] because state is saved +# You can grab all the elements of an iterable or iterator by call of list(). +list(our_iterable) # => Returns ["one", "two", "three"] +list(our_iterator) # => Returns [] because state is saved -#################################################### -## 4. Functions -#################################################### +#################################################### +## 4. Functions +#################################################### -# Use "def" to create new functions -def add(x, y): - print("x is {} and y is {}".format(x, y)) - return x + y # Return values with a return statement +# Use "def" to create new functions +def add(x, y): + print("x is {} and y is {}".format(x, y)) + return x + y # Return values with a return statement -# Calling functions with parameters -add(5, 6) # => prints out "x is 5 and y is 6" and returns 11 +# Calling functions with parameters +add(5, 6) # => prints out "x is 5 and y is 6" and returns 11 -# Another way to call functions is with keyword arguments -add(y=6, x=5) # Keyword arguments can arrive in any order. +# Another way to call functions is with keyword arguments +add(y=6, x=5) # Keyword arguments can arrive in any order. -# You can define functions that take a variable number of -# positional arguments -def varargs(*args): +# You can define functions that take a variable number of +# positional arguments +def varargs(*args):  return args -varargs(1, 2, 3) # => (1, 2, 3) +varargs(1, 2, 3) # => (1, 2, 3) -# You can define functions that take a variable number of -# keyword arguments, as well -def keyword_args(**kwargs): +# You can define functions that take a variable number of +# keyword arguments, as well +def keyword_args(**kwargs):  return kwargs -# Let's call it to see what happens -keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} +# Let's call it to see what happens +keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} -# You can do both at once, if you like -def all_the_args(*args, **kwargs): - print(args) - print(kwargs) +# You can do both at once, if you like +def all_the_args(*args, **kwargs): + print(args) + print(kwargs) """ all_the_args(1, 2, a=3, b=4) prints:  (1, 2)  {"a": 3, "b": 4} """ -# When calling functions, you can do the opposite of args/kwargs! -# Use * to expand tuples and use ** to expand kwargs. -args = (1, 2, 3, 4) -kwargs = {"a": 3, "b": 4} -all_the_args(*args) # equivalent to all_the_args(1, 2, 3, 4) -all_the_args(**kwargs) # equivalent to all_the_args(a=3, b=4) -all_the_args(*args, **kwargs) # equivalent to all_the_args(1, 2, 3, 4, a=3, b=4) - -# Returning multiple values (with tuple assignments) -def swap(x, y): - return y, x # Return multiple values as a tuple without the parenthesis. - # (Note: parenthesis have been excluded but can be included) - -x = 1 -y = 2 -x, y = swap(x, y) # => x = 2, y = 1 -# (x, y) = swap(x,y) # Again parenthesis have been excluded but can be included. - -# Function Scope -x = 5 - -def set_x(num): - # Local var x not the same as global variable x - x = num # => 43 - print(x) # => 43 - -def set_global_x(num): +# When calling functions, you can do the opposite of args/kwargs! +# Use * to expand tuples and use ** to expand kwargs. +args = (1, 2, 3, 4) +kwargs = {"a": 3, "b": 4} +all_the_args(*args) # equivalent: all_the_args(1, 2, 3, 4) +all_the_args(**kwargs) # equivalent: all_the_args(a=3, b=4) +all_the_args(*args, **kwargs) # equivalent: all_the_args(1, 2, 3, 4, a=3, b=4) + +# Returning multiple values (with tuple assignments) +def swap(x, y): + return y, x # Return multiple values as a tuple without the parenthesis. + # (Note: parenthesis have been excluded but can be included) + +x = 1 +y = 2 +x, y = swap(x, y) # => x = 2, y = 1 +# (x, y) = swap(x,y) # Again the use of parenthesis is optional. + +# global scope +x = 5 + +def set_x(num): + # local scope begins here + # local var x not the same as global var x + x = num # => 43 + print(x) # => 43 + +def set_global_x(num): + # global indicates that particular var lives in the global scope  global x - print(x) # => 5 - x = num # global var x is now set to 6 - print(x) # => 6 + print(x) # => 5 + x = num # global var x is now set to 6 + print(x) # => 6 -set_x(43) -set_global_x(6) +set_x(43) +set_global_x(6) +""" +prints: + 43 + 5 + 6 +""" -# Python has first class functions -def create_adder(x): - def adder(y): +# Python has first class functions +def create_adder(x): + def adder(y):  return x + y  return adder -add_10 = create_adder(10) -add_10(3) # => 13 +add_10 = create_adder(10) +add_10(3) # => 13 -# There are also anonymous functions -(lambda x: x > 2)(3) # => True -(lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 +# There are also anonymous functions +(lambda x: x > 2)(3) # => True +(lambda x, y: x ** 2 + y ** 2)(2, 1) # => 5 -# There are built-in higher order functions -list(map(add_10, [1, 2, 3])) # => [11, 12, 13] -list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] +# There are built-in higher order functions +list(map(add_10, [1, 2, 3])) # => [11, 12, 13] +list(map(max, [1, 2, 3], [4, 2, 1])) # => [4, 2, 3] -list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] +list(filter(lambda x: x > 5, [3, 4, 5, 6, 7])) # => [6, 7] -# We can use list comprehensions for nice maps and filters -# List comprehension stores the output as a list which can itself be a nested list -[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] -[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] +# We can use list comprehensions for nice maps and filters +# List comprehension stores the output as a list (which itself may be nested). +[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] +[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] -# You can construct set and dict comprehensions as well. -{x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} -{x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} +# You can construct set and dict comprehensions as well. +{x for x in 'abcddeef' if x not in 'abc'} # => {'d', 'e', 'f'} +{x: x**2 for x in range(5)} # => {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} -#################################################### -## 5. Modules -#################################################### +#################################################### +## 5. Modules +#################################################### -# You can import modules -import math -print(math.sqrt(16)) # => 4.0 +# You can import modules +import math +print(math.sqrt(16)) # => 4.0 -# You can get specific functions from a module -from math import ceil, floor -print(ceil(3.7)) # => 4.0 -print(floor(3.7)) # => 3.0 +# You can get specific functions from a module +from math import ceil, floor +print(ceil(3.7)) # => 4.0 +print(floor(3.7)) # => 3.0 -# You can import all functions from a module. -# Warning: this is not recommended -from math import * +# You can import all functions from a module. +# Warning: this is not recommended +from math import * -# You can shorten module names -import math as m -math.sqrt(16) == m.sqrt(16) # => True +# You can shorten module names +import math as m +math.sqrt(16) == m.sqrt(16) # => True -# Python modules are just ordinary Python files. You -# can write your own, and import them. The name of the -# module is the same as the name of the file. +# Python modules are just ordinary Python files. You +# can write your own, and import them. The name of the +# module is the same as the name of the file. -# You can find out which functions and attributes -# are defined in a module. -import math -dir(math) +# You can find out which functions and attributes +# are defined in a module. +import math +dir(math) -# If you have a Python script named math.py in the same -# folder as your current script, the file math.py will -# be loaded instead of the built-in Python module. -# This happens because the local folder has priority -# over Python's built-in libraries. +# If you have a Python script named math.py in the same +# folder as your current script, the file math.py will +# be loaded instead of the built-in Python module. +# This happens because the local folder has priority +# over Python's built-in libraries. -#################################################### -## 6. Classes -#################################################### +#################################################### +## 6. Classes +#################################################### -# We use the "class" statement to create a class -class Human: +# We use the "class" statement to create a class +class Human: - # A class attribute. It is shared by all instances of this class + # A class attribute. It is shared by all instances of this class  species = "H. sapiens" - # Basic initializer, this is called when this class is instantiated. - # Note that the double leading and trailing underscores denote objects - # or attributes that are used by Python but that live in user-controlled - # namespaces. Methods(or objects or attributes) like: __init__, __str__, - # __repr__ etc. are called special methods (or sometimes called dunder methods) - # You should not invent such names on your own. - def __init__(self, name): - # Assign the argument to the instance's name attribute - self.name = name - - # Initialize property - self._age = 0 - - # An instance method. All methods take "self" as the first argument - def say(self, msg): - print("{name}: {message}".format(name=self.name, message=msg)) - - # Another instance method - def sing(self): + # Basic initializer, this is called when this class is instantiated. + # Note that the double leading and trailing underscores denote objects + # or attributes that are used by Python but that live in user-controlled + # namespaces. Methods(or objects or attributes) like: __init__, __str__, + # __repr__ etc. are called special methods (or sometimes called dunder + # methods). You should not invent such names on your own. + def __init__(self, name): + # Assign the argument to the instance's name attribute + self.name = name + + # Initialize property + self._age = 0 + + # An instance method. All methods take "self" as the first argument + def say(self, msg): + print("{name}: {message}".format(name=self.name, message=msg)) + + # Another instance method + def sing(self):  return 'yo... yo... microphone check... one two... one two...' - # A class method is shared among all instances - # They are called with the calling class as the first argument + # A class method is shared among all instances + # They are called with the calling class as the first argument  @classmethod - def get_species(cls): - return cls.species + def get_species(cls): + return cls.species - # A static method is called without a class or instance reference + # A static method is called without a class or instance reference  @staticmethod - def grunt(): + def grunt():  return "*grunt*" - # A property is just like a getter. - # It turns the method age() into a read-only attribute of the same name. - # There's no need to write trivial getters and setters in Python, though. + # A property is just like a getter. + # It turns the method age() into a read-only attribute of the same name. + # There's no need to write trivial getters and setters in Python, though.  @property - def age(self): - return self._age + def age(self): + return self._age - # This allows the property to be set + # This allows the property to be set  @age.setter - def age(self, age): - self._age = age + def age(self, age): + self._age = age - # This allows the property to be deleted + # This allows the property to be deleted  @age.deleter - def age(self): - del self._age + def age(self): + del self._age -# When a Python interpreter reads a source file it executes all its code. -# This __name__ check makes sure this code block is only executed when this -# module is the main program. +# When a Python interpreter reads a source file it executes all its code. +# This __name__ check makes sure this code block is only executed when this +# module is the main program. if __name__ == '__main__': - # Instantiate a class + # Instantiate a class  i = Human(name="Ian") - i.say("hi") # "Ian: hi" + i.say("hi") # "Ian: hi"  j = Human("Joel") - j.say("hello") # "Joel: hello" - # i and j are instances of type Human, or in other words: they are Human objects + j.say("hello") # "Joel: hello" + # i and j are instances of type Human; i.e., they are Human objects. - # Call our class method - i.say(i.get_species()) # "Ian: H. sapiens" - # Change the shared attribute + # Call our class method + i.say(i.get_species()) # "Ian: H. sapiens" + # Change the shared attribute  Human.species = "H. neanderthalensis" - i.say(i.get_species()) # => "Ian: H. neanderthalensis" - j.say(j.get_species()) # => "Joel: H. neanderthalensis" + i.say(i.get_species()) # => "Ian: H. neanderthalensis" + j.say(j.get_species()) # => "Joel: H. neanderthalensis" - # Call the static method - print(Human.grunt()) # => "*grunt*" + # Call the static method + print(Human.grunt()) # => "*grunt*" - # Static methods can be called by instances too - print(i.grunt()) # => "*grunt*" + # Static methods can be called by instances too + print(i.grunt()) # => "*grunt*" - # Update the property for this instance - i.age = 42 - # Get the property - i.say(i.age) # => "Ian: 42" - j.say(j.age) # => "Joel: 0" - # Delete the property + # Update the property for this instance + i.age = 42 + # Get the property + i.say(i.age) # => "Ian: 42" + j.say(j.age) # => "Joel: 0" + # Delete the property  del i.age - # i.age # => this would raise an AttributeError + # i.age # => this would raise an AttributeError -#################################################### -## 6.1 Inheritance -#################################################### +#################################################### +## 6.1 Inheritance +#################################################### -# Inheritance allows new child classes to be defined that inherit methods and -# variables from their parent class. +# Inheritance allows new child classes to be defined that inherit methods and +# variables from their parent class. -# Using the Human class defined above as the base or parent class, we can -# define a child class, Superhero, which inherits the class variables like -# "species", "name", and "age", as well as methods, like "sing" and "grunt" -# from the Human class, but can also have its own unique properties. +# Using the Human class defined above as the base or parent class, we can +# define a child class, Superhero, which inherits the class variables like +# "species", "name", and "age", as well as methods, like "sing" and "grunt" +# from the Human class, but can also have its own unique properties. -# To take advantage of modularization by file you could place the classes above in their own files, -# say, human.py +# To take advantage of modularization by file you could place the classes above +# in their own files, say, human.py -# To import functions from other files use the following format -# from "filename-without-extension" import "function-or-class" +# To import functions from other files use the following format +# from "filename-without-extension" import "function-or-class" -from human import Human +from human import Human -# Specify the parent class(es) as parameters to the class definition -class Superhero(Human): +# Specify the parent class(es) as parameters to the class definition +class Superhero(Human): - # If the child class should inherit all of the parent's definitions without - # any modifications, you can just use the "pass" keyword (and nothing else) - # but in this case it is commented out to allow for a unique child class: - # pass + # If the child class should inherit all of the parent's definitions without + # any modifications, you can just use the "pass" keyword (and nothing else) + # but in this case it is commented out to allow for a unique child class: + # pass - # Child classes can override their parents' attributes + # Child classes can override their parents' attributes  species = 'Superhuman' - # Children automatically inherit their parent class's constructor including - # its arguments, but can also define additional arguments or definitions - # and override its methods such as the class constructor. - # This constructor inherits the "name" argument from the "Human" class and - # adds the "superpower" and "movie" arguments: - def __init__(self, name, movie=False, + # Children automatically inherit their parent class's constructor including + # its arguments, but can also define additional arguments or definitions + # and override its methods such as the class constructor. + # This constructor inherits the "name" argument from the "Human" class and + # adds the "superpower" and "movie" arguments: + def __init__(self, name, movie=False,  superpowers=["super strength", "bulletproofing"]): - # add additional class attributes: - self.fictional = True - self.movie = movie - # be aware of mutable default values, since defaults are shared - self.superpowers = superpowers + # add additional class attributes: + self.fictional = True + self.movie = movie + # be aware of mutable default values, since defaults are shared + self.superpowers = superpowers - # The "super" function lets you access the parent class's methods - # that are overridden by the child, in this case, the __init__ method. - # This calls the parent class constructor: - super().__init__(name) + # The "super" function lets you access the parent class's methods + # that are overridden by the child, in this case, the __init__ method. + # This calls the parent class constructor: + super().__init__(name) - # override the sing method - def sing(self): + # override the sing method + def sing(self):  return 'Dun, dun, DUN!' - # add an additional instance method - def boast(self): - for power in self.superpowers: - print("I wield the power of {pow}!".format(pow=power)) + # add an additional instance method + def boast(self): + for power in self.superpowers: + print("I wield the power of {pow}!".format(pow=power)) if __name__ == '__main__':  sup = Superhero(name="Tick") - # Instance type checks - if isinstance(sup, Human): - print('I am human') - if type(sup) is Superhero: - print('I am a superhero') + # Instance type checks + if isinstance(sup, Human): + print('I am human') + if type(sup) is Superhero: + print('I am a superhero') - # Get the Method Resolution search Order used by both getattr() and super() - # This attribute is dynamic and can be updated - print(Superhero.__mro__) # => (, - # => , ) + # Get the Method Resolution search Order used by both getattr() and super() + # This attribute is dynamic and can be updated + print(Superhero.__mro__) # => (, + # => , ) - # Calls parent method but uses its own class attribute - print(sup.get_species()) # => Superhuman + # Calls parent method but uses its own class attribute + print(sup.get_species()) # => Superhuman - # Calls overridden method - print(sup.sing()) # => Dun, dun, DUN! + # Calls overridden method + print(sup.sing()) # => Dun, dun, DUN! - # Calls method from Human - sup.say('Spoon') # => Tick: Spoon + # Calls method from Human + sup.say('Spoon') # => Tick: Spoon - # Call method that exists only in Superhero - sup.boast() # => I wield the power of super strength! - # => I wield the power of bulletproofing! + # Call method that exists only in Superhero + sup.boast() # => I wield the power of super strength! + # => I wield the power of bulletproofing! - # Inherited class attribute - sup.age = 31 - print(sup.age) # => 31 + # Inherited class attribute + sup.age = 31 + print(sup.age) # => 31 - # Attribute that only exists within Superhero - print('Am I Oscar eligible? ' + str(sup.movie)) + # Attribute that only exists within Superhero + print('Am I Oscar eligible? ' + str(sup.movie)) -#################################################### -## 6.2 Multiple Inheritance -#################################################### +#################################################### +## 6.2 Multiple Inheritance +#################################################### -# Another class definition -# bat.py -class Bat: +# Another class definition +# bat.py +class Bat:  species = 'Baty' - def __init__(self, can_fly=True): - self.fly = can_fly + def __init__(self, can_fly=True): + self.fly = can_fly - # This class also has a say method - def say(self, msg): + # This class also has a say method + def say(self, msg):  msg = '... ... ...'  return msg - # And its own method as well - def sonar(self): + # And its own method as well + def sonar(self):  return '))) ... (((' if __name__ == '__main__':  b = Bat() - print(b.say('hello')) - print(b.fly) - - -# And yet another class definition that inherits from Superhero and Bat -# superhero.py -from superhero import Superhero -from bat import Bat - -# Define Batman as a child that inherits from both Superhero and Bat -class Batman(Superhero, Bat): - - def __init__(self, *args, **kwargs): - # Typically to inherit attributes you have to call super: - # super(Batman, self).__init__(*args, **kwargs) - # However we are dealing with multiple inheritance here, and super() - # only works with the next base class in the MRO list. - # So instead we explicitly call __init__ for all ancestors. - # The use of *args and **kwargs allows for a clean way to pass arguments, - # with each parent "peeling a layer of the onion". - Superhero.__init__(self, 'anonymous', movie=True, + print(b.say('hello')) + print(b.fly) + + +# And yet another class definition that inherits from Superhero and Bat +# superhero.py +from superhero import Superhero +from bat import Bat + +# Define Batman as a child that inherits from both Superhero and Bat +class Batman(Superhero, Bat): + + def __init__(self, *args, **kwargs): + # Typically to inherit attributes you have to call super: + # super(Batman, self).__init__(*args, **kwargs) + # However we are dealing with multiple inheritance here, and super() + # only works with the next base class in the MRO list. + # So instead we explicitly call __init__ for all ancestors. + # The use of *args and **kwargs allows for a clean way to pass + # arguments, with each parent "peeling a layer of the onion". + Superhero.__init__(self, 'anonymous', movie=True,  superpowers=['Wealthy'], *args, **kwargs) - Bat.__init__(self, *args, can_fly=False, **kwargs) - # override the value for the name attribute - self.name = 'Sad Affleck' + Bat.__init__(self, *args, can_fly=False, **kwargs) + # override the value for the name attribute + self.name = 'Sad Affleck' - def sing(self): + def sing(self):  return 'nan nan nan nan nan batman!' if __name__ == '__main__':  sup = Batman() - # Get the Method Resolution search Order used by both getattr() and super(). - # This attribute is dynamic and can be updated - print(Batman.__mro__) # => (, - # => , - # => , - # => , ) + # Get the Method Resolution search Order used by both getattr() and super(). + # This attribute is dynamic and can be updated + print(Batman.__mro__) # => (, + # => , + # => , + # => , ) - # Calls parent method but uses its own class attribute - print(sup.get_species()) # => Superhuman + # Calls parent method but uses its own class attribute + print(sup.get_species()) # => Superhuman - # Calls overridden method - print(sup.sing()) # => nan nan nan nan nan batman! + # Calls overridden method + print(sup.sing()) # => nan nan nan nan nan batman! - # Calls method from Human, because inheritance order matters - sup.say('I agree') # => Sad Affleck: I agree + # Calls method from Human, because inheritance order matters + sup.say('I agree') # => Sad Affleck: I agree - # Call method that exists only in 2nd ancestor - print(sup.sonar()) # => ))) ... ((( + # Call method that exists only in 2nd ancestor + print(sup.sonar()) # => ))) ... ((( - # Inherited class attribute - sup.age = 100 - print(sup.age) # => 100 + # Inherited class attribute + sup.age = 100 + print(sup.age) # => 100 - # Inherited attribute from 2nd ancestor whose default value was overridden. - print('Can I fly? ' + str(sup.fly)) # => Can I fly? False + # Inherited attribute from 2nd ancestor whose default value was overridden. + print('Can I fly? ' + str(sup.fly)) # => Can I fly? False -#################################################### -## 7. Advanced -#################################################### +#################################################### +## 7. Advanced +#################################################### -# Generators help you make lazy code. -def double_numbers(iterable): +# Generators help you make lazy code. +def double_numbers(iterable):  for i in iterable:  yield i + i -# Generators are memory-efficient because they only load the data needed to -# process the next value in the iterable. This allows them to perform -# operations on otherwise prohibitively large value ranges. -# NOTE: `range` replaces `xrange` in Python 3. -for i in double_numbers(range(1, 900000000)): # `range` is a generator. - print(i) - if i >= 30: +# Generators are memory-efficient because they only load the data needed to +# process the next value in the iterable. This allows them to perform +# operations on otherwise prohibitively large value ranges. +# NOTE: `range` replaces `xrange` in Python 3. +for i in double_numbers(range(1, 900000000)): # `range` is a generator. + print(i) + if i >= 30:  break -# Just as you can create a list comprehension, you can create generator -# comprehensions as well. -values = (-x for x in [1,2,3,4,5]) +# Just as you can create a list comprehension, you can create generator +# comprehensions as well. +values = (-x for x in [1,2,3,4,5]) for x in values: - print(x) # prints -1 -2 -3 -4 -5 to console/terminal + print(x) # prints -1 -2 -3 -4 -5 to console/terminal -# You can also cast a generator comprehension directly to a list. -values = (-x for x in [1,2,3,4,5]) -gen_to_list = list(values) -print(gen_to_list) # => [-1, -2, -3, -4, -5] +# You can also cast a generator comprehension directly to a list. +values = (-x for x in [1,2,3,4,5]) +gen_to_list = list(values) +print(gen_to_list) # => [-1, -2, -3, -4, -5] -# Decorators -# In this example `beg` wraps `say`. If say_please is True then it -# will change the returned message. -from functools import wraps +# Decorators +# In this example `beg` wraps `say`. If say_please is True then it +# will change the returned message. +from functools import wraps -def beg(target_function): +def beg(target_function):  @wraps(target_function) - def wrapper(*args, **kwargs): + def wrapper(*args, **kwargs):  msg, say_please = target_function(*args, **kwargs)  if say_please:  return "{} {}".format(msg, "Please! I am poor :(") @@ -992,10 +1008,10 @@ @beg -def say(say_please=False): +def say(say_please=False):  msg = "Can you buy me a beer?"  return msg, say_please -print(say()) # Can you buy me a beer? -print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( +print(say()) # Can you buy me a beer? +print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( diff --git a/tests/results/16 b/tests/results/16 index b653ffd5..263cd83a 100644 --- a/tests/results/16 +++ b/tests/results/16 @@ -2,15 +2,15 @@ 1ns Main memory reference: Send 2,000 bytes Read 1,000,000 bytes ▗▖ 100ns over commodity network: sequentially from SSD: - ▗▖ 31ns 38.876us + ▗▖ 15ns 24.49us L1 cache reference: 1ns ▗ ▗  ▗▖ 1.0us - ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ SSD random read: 16.0us Disk seek: 2.332582ms + ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ SSD random read: 16.0us Disk seek: 2.03063ms Branch mispredict: 3ns  ▗▖▗ ▗▖▗▖  ▗▖▗▖▗▖  Compress 1KB wth Snappy: Read 1,000,000 bytes Read 1,000,000 bytes L2 cache reference: 4ns 2.0us sequentially from memory: sequentially from disk: -▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ 2.355us 717.936us +▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ 1.483us 544.094us ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗ ▗  Mutex lock/unlock: 16ns   ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  Round trip Packet roundtrip diff --git a/tests/results/17 b/tests/results/17 index 6fb087ff..a5b95b92 100644 --- a/tests/results/17 +++ b/tests/results/17 @@ -1,120 +1,120 @@  cheat.sheets:az  -# Microsoft Azure CLI 2.0 -# Command-line tools for Azure +# Microsoft Azure CLI 2.0 +# Command-line tools for Azure -# Install Azure CLI 2.0 with one curl command. -curl -L https://aka.ms/InstallAzureCli | bash +# Install Azure CLI 2.0 with one curl command. +curl -L https://aka.ms/InstallAzureCli | bash -# create a resource group named "MyRG" in the 'westus2' region -az group create -n MyRG -l westus2 +# create a resource group named "MyRG" in the 'westus2' region +az group create -n MyRG -l westus2 -# create a Linux VM using the UbuntuTLS image, -# with two attached storage disks of 10 GB and 20 GB -az vm create -n MyLinuxVM -g MyRG \ - --ssh-key-value $HOME/.ssh/id_rsa.pub --image UbuntuLTS \ - --data-disk-sizes-gb 10 20 +# create a Linux VM using the UbuntuTLS image, +# with two attached storage disks of 10 GB and 20 GB +az vm create -n MyLinuxVM -g MyRG \ + --ssh-key-value $HOME/.ssh/id_rsa.pub --image UbuntuLTS \ + --data-disk-sizes-gb 10 20 -# list VMs -az vm list --output table +# list VMs +az vm list --output table -# list only VMs having distinct state -az vm list -d --query "[?powerState=='VM running']" --output table +# list only VMs having distinct state +az vm list -d --query "[?powerState=='VM running']" --output table -# delete VM (with the name MyLinuxVM in the group MyRG) -az vm delete -g MyRG -n MyLinuxVM --yes +# delete VM (with the name MyLinuxVM in the group MyRG) +az vm delete -g MyRG -n MyLinuxVM --yes -# Delete all VMs in a resource group -az vm delete --ids $(az vm list -g MyRG --query "[].id" -o tsv) +# Delete all VMs in a resource group +az vm delete --ids $(az vm list -g MyRG --query "[].id" -o tsv) -# Create an Image based on a running VM -az vm deallocate -g MyRG -n MyLinuxVM -az vm generalize -g MyRG -n MyLinuxVM -az image create --resource-group MyRG --name MyTestImage --source MyLinuxVM +# Create an Image based on a running VM +az vm deallocate -g MyRG -n MyLinuxVM +az vm generalize -g MyRG -n MyLinuxVM +az image create --resource-group MyRG --name MyTestImage --source MyLinuxVM -# Running VM based on a VHD -az storage blob upload --account-name "${account_name}" \ - --account-key "${account_key}" --container-name "${container}" --type page \ - --file "${file}" --name "${vhd}" -az disk create \ - --resource-group "${resource_group}" \ - --name myManagedDisk \ - --source "https://${account_name}.blob.core.windows.net/${container}/${vhd}" +# Running VM based on a VHD +az storage blob upload --account-name "${account_name}" \ + --account-key "${account_key}" --container-name "${container}" --type page \ + --file "${file}" --name "${vhd}" +az disk create \ + --resource-group "${resource_group}" \ + --name myManagedDisk \ + --source "https://${account_name}.blob.core.windows.net/${container}/${vhd}" -# open port -az vm open-port --resource-group MyRG --name MyLinuxVM --port 443 --priority 899 +# open port +az vm open-port --resource-group MyRG --name MyLinuxVM --port 443 --priority 899 -# Show storage accounts -az storage account list --output table +# Show storage accounts +az storage account list --output table -# Show containers for an account -az storage container list --account-name mystorageaccount --output table +# Show containers for an account +az storage container list --account-name mystorageaccount --output table -# Show blobs in a container -az storage blob list --account-name mystorageaccount \ - --container-name mycontainer --output table +# Show blobs in a container +az storage blob list --account-name mystorageaccount \ + --container-name mycontainer --output table -# list account keys -az storage account keys list --account-name STORAGE_NAME --resource-group RESOURCE_GROUP +# list account keys +az storage account keys list --account-name STORAGE_NAME --resource-group RESOURCE_GROUP -# Show own images -az image list --output table +# Show own images +az image list --output table -# Configure default storage location -az configure --defaults location=eastus2 +# Configure default storage location +az configure --defaults location=eastus2 -# Show disks -az disk list --output table +# Show disks +az disk list --output table -# Copy blob -az storage blob copy start \ - --source-uri 'https://xxx.blob.core.windows.net/jzwuuuzzapn0/abcd?...' \ - --account-key XXXXXXXXXX== \ - --account-name destaccount \ - --destination-container vms \ - --destination-blob DESTINATION-blob.vhd +# Copy blob +az storage blob copy start \ + --source-uri 'https://xxx.blob.core.windows.net/jzwuuuzzapn0/abcd?...' \ + --account-key XXXXXXXXXX== \ + --account-name destaccount \ + --destination-container vms \ + --destination-blob DESTINATION-blob.vhd -# List virtual networks -az network vnet list --output table +# List virtual networks +az network vnet list --output table -# List virtual networks adapters -az network nic list --output table +# List virtual networks adapters +az network nic list --output table -# List public IP addresses used by the VMs -az vm list-ip-addresses --output table +# List public IP addresses used by the VMs +az vm list-ip-addresses --output table -# create snapshot -az snapshot create --resource-group IC-EXASOL-001 --source vm1-disk1 -n vm1-snap1 +# create snapshot +az snapshot create --resource-group IC-EXASOL-001 --source vm1-disk1 -n vm1-snap1 -# create SAS url for a snapshot -az snapshot grant-access --resource-group IC-EXASOL-001 --name vm1-snap1\ - --duration-in-seconds 36000 --query '[accessSas]' -o tsv +# create SAS url for a snapshot +az snapshot grant-access --resource-group IC-EXASOL-001 --name vm1-snap1\ + --duration-in-seconds 36000 --query '[accessSas]' -o tsv -# attach disk -az vm disk attach --vm-name vm1 -g RESOURCE_GROUP --disk DISK1_ID +# attach disk +az vm disk attach --vm-name vm1 -g RESOURCE_GROUP --disk DISK1_ID -# detach disk -az vm disk detach --vm-name vm1 -g RESOURCE_GROUP --name DISK1_ID +# detach disk +az vm disk detach --vm-name vm1 -g RESOURCE_GROUP --name DISK1_ID  tldr:az  -# az -# The official CLI tool for Microsoft Azure. -# Some subcommands such as `az login` have their own usage documentation. -# More information: . +# az +# The official CLI tool for Microsoft Azure. +# Some subcommands such as `az login` have their own usage documentation. +# More information: . -# Log in to Azure: -az login +# Log in to Azure: +az login -# Manage azure subscription information: -az account +# Manage azure subscription information: +az account -# List all Azure Managed Disks: -az disk list +# List all Azure Managed Disks: +az disk list -# List all Azure virtual machines: -az vm list +# List all Azure virtual machines: +az vm list -# Manage Azure Kubernetes Services: -az aks +# Manage Azure Kubernetes Services: +az aks -# Manage Azure Network resources: -az network +# Manage Azure Network resources: +az network diff --git a/tests/results/18 b/tests/results/18 index 651c8c08..279a2ef9 100644 --- a/tests/results/18 +++ b/tests/results/18 @@ -1,19 +1,19 @@ >>> s = 'abcdefgh' ->>> n, m, char, chars = 2, 3, 'd', 'cd' ->>> # starting from n=2 characters in and m=3 in length; ->>> s[n-1:n+m-1] +>>> n, m, char, chars = 2, 3, 'd', 'cd' +>>> # starting from n=2 characters in and m=3 in length; +>>> s[n-1:n+m-1] 'bcd' ->>> # starting from n characters in, up to the end of the string; ->>> s[n-1:] +>>> # starting from n characters in, up to the end of the string; +>>> s[n-1:] 'bcdefgh' ->>> # whole string minus last character; ->>> s[:-1] +>>> # whole string minus last character; +>>> s[:-1] 'abcdefg' ->>> # starting from a known character char="d" within the string and of m length; +>>> # starting from a known character char="d" within the string and of m length; >>> indx = s.index(char) >>> s[indx:indx+m] 'def' ->>> # starting from a known substring chars="cd" within the string and of m length. +>>> # starting from a known substring chars="cd" within the string and of m length. >>> indx = s.index(chars) >>> s[indx:indx+m] 'cde' diff --git a/tests/results/2 b/tests/results/2 index 3d5b767b..530d74b6 100644 --- a/tests/results/2 +++ b/tests/results/2 @@ -1,47 +1,63 @@  cheat:ls  -# To display everything in , excluding hidden files: -ls <dir> +# To display everything in , excluding hidden files: +ls <dir> -# To display everything in , including hidden files: -ls -a <dir> +# To display everything in , including hidden files: +ls -a <dir> -# To display all files, along with the size (with unit suffixes) and timestamp -ls -lh <dir> +# To display all files, along with the size (with unit suffixes) and timestamp: +ls -lh <dir> -# To display files, sorted by size: -ls -S <dir> +# To display files, sorted by size: +ls -S <dir> -# To display directories only: -ls -d */ <dir> +# To display directories only: +ls -d */ <dir> -# To display directories only, include hidden: -ls -d .*/ */ <dir> +# To display directories only, include hidden: +ls -d .*/ */ <dir> + +# To display all files sorted by changed date, most recent first: +ls -ltc  + +# To display files sorted by create time: +ls -lt + +# To display files in a single column: +ls -1 + +# To show ACLs (MacOS): +# see also `cheat chmod` for `/bin/chmod` options for ACLs +/bin/ls -le + +# To show all the subtree files (Recursive Mode): +ls -R  tldr:ls  -# ls -# List directory contents. -# More information: . +# ls +# List directory contents. +# More information: . -# List files one per line: -ls -1 +# List files one per line: +ls -1 -# List all files, including hidden files: -ls -a +# List all files, including hidden files: +ls -a -# List all files, with trailing `/` added to directory names: -ls -F +# List all files, with trailing `/` added to directory names: +ls -F -# Long format list (permissions, ownership, size, and modification date) of all files: -ls -la +# Long format list (permissions, ownership, size, and modification date) of all files: +ls -la -# Long format list with size displayed using human-readable units (KiB, MiB, GiB): -ls -lh +# Long format list with size displayed using human-readable units (KiB, MiB, GiB): +ls -lh -# Long format list sorted by size (descending): -ls -lS +# Long format list sorted by size (descending): +ls -lS -# Long format list of all files, sorted by modification date (oldest first): -ls -ltr +# Long format list of all files, sorted by modification date (oldest first): +ls -ltr -# Only list directories: -ls -d */ +# Only list directories: +ls -d */ diff --git a/tests/results/21 b/tests/results/21 index bfd13d39..6dd970d0 100644 --- a/tests/results/21 +++ b/tests/results/21 @@ -1,606 +1,606 @@ -// Single-line comments start with two slashes. -/* Multiline comments start with slash-star, - and end with star-slash */ +// Single-line comments start with two slashes. +/* Multiline comments start with slash-star, + and end with star-slash */ -// Statements can be terminated by ; +// Statements can be terminated by ; doStuff(); -// ... but they don't have to be, as semicolons are automatically inserted -// wherever there's a newline, except in certain cases. +// ... but they don't have to be, as semicolons are automatically inserted +// wherever there's a newline, except in certain cases. doStuff() -// Because those cases can cause unexpected results, we'll keep on using -// semicolons in this guide. +// Because those cases can cause unexpected results, we'll keep on using +// semicolons in this guide. -/////////////////////////////////// -// 1. Numbers, Strings and Operators +/////////////////////////////////// +// 1. Numbers, Strings and Operators -// JavaScript has one number type (which is a 64-bit IEEE 754 double). -// Doubles have a 52-bit mantissa, which is enough to store integers -// up to about 9✕10¹⁵ precisely. -3; // = 3 -1.5; // = 1.5 +// JavaScript has one number type (which is a 64-bit IEEE 754 double). +// Doubles have a 52-bit mantissa, which is enough to store integers +// up to about 9✕10¹⁵ precisely. +3; // = 3 +1.5; // = 1.5 -// Some basic arithmetic works as you'd expect. -1 + 1; // = 2 -0.1 + 0.2; // = 0.30000000000000004 -8 - 1; // = 7 -10 * 2; // = 20 -35 / 5; // = 7 +// Some basic arithmetic works as you'd expect. +1 + 1; // = 2 +0.1 + 0.2; // = 0.30000000000000004 +8 - 1; // = 7 +10 * 2; // = 20 +35 / 5; // = 7 -// Including uneven division. -5 / 2; // = 2.5 +// Including uneven division. +5 / 2; // = 2.5 -// And modulo division. -10 % 2; // = 0 -30 % 4; // = 2 -18.5 % 7; // = 4.5 +// And modulo division. +10 % 2; // = 0 +30 % 4; // = 2 +18.5 % 7; // = 4.5 -// Bitwise operations also work; when you perform a bitwise operation your float -// is converted to a signed int *up to* 32 bits. -1 << 2; // = 4 +// Bitwise operations also work; when you perform a bitwise operation your float +// is converted to a signed int *up to* 32 bits. +1 << 2; // = 4 -// Precedence is enforced with parentheses. -(1 + 3) * 2; // = 8 +// Precedence is enforced with parentheses. +(1 + 3) * 2; // = 8 -// There are three special not-a-real-number values: -Infinity; // result of e.g. 1/0 --Infinity; // result of e.g. -1/0 -NaN; // result of e.g. 0/0, stands for 'Not a Number' +// There are three special not-a-real-number values: +Infinity; // result of e.g. 1/0 +-Infinity; // result of e.g. -1/0 +NaN; // result of e.g. 0/0, stands for 'Not a Number' -// There's also a boolean type. +// There's also a boolean type. true; false; -// Strings are created with ' or ". +// Strings are created with ' or ". 'abc'; "Hello, world"; -// Negation uses the ! symbol -!true; // = false -!false; // = true +// Negation uses the ! symbol +!true; // = false +!false; // = true -// Equality is === -1 === 1; // = true -2 === 1; // = false +// Equality is === +1 === 1; // = true +2 === 1; // = false -// Inequality is !== -1 !== 1; // = false -2 !== 1; // = true +// Inequality is !== +1 !== 1; // = false +2 !== 1; // = true -// More comparisons -1 < 10; // = true -1 > 10; // = false -2 <= 2; // = true -2 >= 2; // = true +// More comparisons +1 < 10; // = true +1 > 10; // = false +2 <= 2; // = true +2 >= 2; // = true -// Strings are concatenated with + -"Hello " + "world!"; // = "Hello world!" +// Strings are concatenated with + +"Hello " + "world!"; // = "Hello world!" -// ... which works with more than just strings -"1, 2, " + 3; // = "1, 2, 3" -"Hello " + ["world", "!"]; // = "Hello world,!" +// ... which works with more than just strings +"1, 2, " + 3; // = "1, 2, 3" +"Hello " + ["world", "!"]; // = "Hello world,!" -// and are compared with < and > -"a" < "b"; // = true +// and are compared with < and > +"a" < "b"; // = true -// Type coercion is performed for comparisons with double equals... -"5" == 5; // = true -null == undefined; // = true +// Type coercion is performed for comparisons with double equals... +"5" == 5; // = true +null == undefined; // = true -// ...unless you use === -"5" === 5; // = false -null === undefined; // = false +// ...unless you use === +"5" === 5; // = false +null === undefined; // = false -// ...which can result in some weird behaviour... -13 + !0; // 14 -"13" + !0; // '13true' +// ...which can result in some weird behaviour... +13 + !0; // 14 +"13" + !0; // '13true' -// You can access characters in a string with `charAt` -"This is a string".charAt(0); // = 'T' +// You can access characters in a string with `charAt` +"This is a string".charAt(0); // = 'T' -// ...or use `substring` to get larger pieces. -"Hello world".substring(0, 5); // = "Hello" +// ...or use `substring` to get larger pieces. +"Hello world".substring(0, 5); // = "Hello" -// `length` is a property, so don't use (). -"Hello".length; // = 5 +// `length` is a property, so don't use (). +"Hello".length; // = 5 -// There's also `null` and `undefined`. -null; // used to indicate a deliberate non-value -undefined; // used to indicate a value is not currently present (although - // `undefined` is actually a value itself) +// There's also `null` and `undefined`. +null; // used to indicate a deliberate non-value +undefined; // used to indicate a value is not currently present (although + // `undefined` is actually a value itself) -// false, null, undefined, NaN, 0 and "" are falsy; everything else is truthy. -// Note that 0 is falsy and "0" is truthy, even though 0 == "0". +// false, null, undefined, NaN, 0 and "" are falsy; everything else is truthy. +// Note that 0 is falsy and "0" is truthy, even though 0 == "0". -/////////////////////////////////// -// 2. Variables, Arrays and Objects +/////////////////////////////////// +// 2. Variables, Arrays and Objects -// Variables are declared with the `var` keyword. JavaScript is dynamically -// typed, so you don't need to specify type. Assignment uses a single `=` -// character. -var someVar = 5; +// Variables are declared with the `var` keyword. JavaScript is dynamically +// typed, so you don't need to specify type. Assignment uses a single `=` +// character. +var someVar = 5; -// If you leave the var keyword off, you won't get an error... -someOtherVar = 10; +// If you leave the var keyword off, you won't get an error... +someOtherVar = 10; -// ...but your variable will be created in the global scope, not in the scope -// you defined it in. +// ...but your variable will be created in the global scope, not in the scope +// you defined it in. -// Variables declared without being assigned to are set to undefined. -var someThirdVar; // = undefined +// Variables declared without being assigned to are set to undefined. +var someThirdVar; // = undefined -// If you want to declare a couple of variables, then you could use a comma -// separator -var someFourthVar = 2, someFifthVar = 4; +// If you want to declare a couple of variables, then you could use a comma +// separator +var someFourthVar = 2, someFifthVar = 4; -// There's shorthand for performing math operations on variables: -someVar += 5; // equivalent to someVar = someVar + 5; someVar is 10 now -someVar *= 10; // now someVar is 100 +// There's shorthand for performing math operations on variables: +someVar += 5; // equivalent to someVar = someVar + 5; someVar is 10 now +someVar *= 10; // now someVar is 100 -// and an even-shorter-hand for adding or subtracting 1 -someVar++; // now someVar is 101 -someVar--; // back to 100 +// and an even-shorter-hand for adding or subtracting 1 +someVar++; // now someVar is 101 +someVar--; // back to 100 -// Arrays are ordered lists of values, of any type. -var myArray = ["Hello", 45, true]; +// Arrays are ordered lists of values, of any type. +var myArray = ["Hello", 45, true]; -// Their members can be accessed using the square-brackets subscript syntax. -// Array indices start at zero. -myArray[1]; // = 45 +// Their members can be accessed using the square-brackets subscript syntax. +// Array indices start at zero. +myArray[1]; // = 45 -// Arrays are mutable and of variable length. +// Arrays are mutable and of variable length. myArray.push("World"); -myArray.length; // = 4 +myArray.length; // = 4 -// Add/Modify at specific index -myArray[3] = "Hello"; +// Add/Modify at specific index +myArray[3] = "Hello"; -// Add and remove element from front or back end of an array -myArray.unshift(3); // Add as the first element -someVar = myArray.shift(); // Remove first element and return it -myArray.push(3); // Add as the last element -someVar = myArray.pop(); // Remove last element and return it +// Add and remove element from front or back end of an array +myArray.unshift(3); // Add as the first element +someVar = myArray.shift(); // Remove first element and return it +myArray.push(3); // Add as the last element +someVar = myArray.pop(); // Remove last element and return it -// Join all elements of an array with semicolon -var myArray0 = [32,false,"js",12,56,90]; -myArray0.join(";"); // = "32;false;js;12;56;90" +// Join all elements of an array with semicolon +var myArray0 = [32,false,"js",12,56,90]; +myArray0.join(";"); // = "32;false;js;12;56;90" -// Get subarray of elements from index 1 (include) to 4 (exclude) -myArray0.slice(1,4); // = [false,"js",12] +// Get subarray of elements from index 1 (include) to 4 (exclude) +myArray0.slice(1,4); // = [false,"js",12] -// Remove 4 elements starting from index 2, and insert there strings -// "hi","wr" and "ld"; return removed subarray -myArray0.splice(2,4,"hi","wr","ld"); // = ["js",12,56,90] -// myArray0 === [32,false,"hi","wr","ld"] +// Remove 4 elements starting from index 2, and insert there strings +// "hi","wr" and "ld"; return removed subarray +myArray0.splice(2,4,"hi","wr","ld"); // = ["js",12,56,90] +// myArray0 === [32,false,"hi","wr","ld"] -// JavaScript's objects are equivalent to "dictionaries" or "maps" in other -// languages: an unordered collection of key-value pairs. -var myObj = {key1: "Hello", key2: "World"}; +// JavaScript's objects are equivalent to "dictionaries" or "maps" in other +// languages: an unordered collection of key-value pairs. +var myObj = {key1: "Hello", key2: "World"}; -// Keys are strings, but quotes aren't required if they're a valid -// JavaScript identifier. Values can be any type. -var myObj = {myKey: "myValue", "my other key": 4}; +// Keys are strings, but quotes aren't required if they're a valid +// JavaScript identifier. Values can be any type. +var myObj = {myKey: "myValue", "my other key": 4}; -// Object attributes can also be accessed using the subscript syntax, -myObj["my other key"]; // = 4 +// Object attributes can also be accessed using the subscript syntax, +myObj["my other key"]; // = 4 -// ... or using the dot syntax, provided the key is a valid identifier. -myObj.myKey; // = "myValue" +// ... or using the dot syntax, provided the key is a valid identifier. +myObj.myKey; // = "myValue" -// Objects are mutable; values can be changed and new keys added. -myObj.myThirdKey = true; +// Objects are mutable; values can be changed and new keys added. +myObj.myThirdKey = true; -// If you try to access a value that's not yet set, you'll get undefined. -myObj.myFourthKey; // = undefined +// If you try to access a value that's not yet set, you'll get undefined. +myObj.myFourthKey; // = undefined -/////////////////////////////////// -// 3. Logic and Control Structures +/////////////////////////////////// +// 3. Logic and Control Structures -// The `if` structure works as you'd expect. -var count = 1; -if (count == 3){ - // evaluated if count is 3 -} else if (count == 4){ - // evaluated if count is 4 -} else { - // evaluated if it's not either 3 or 4 +// The `if` structure works as you'd expect. +var count = 1; +if (count == 3){ + // evaluated if count is 3 +} else if (count == 4){ + // evaluated if count is 4 +} else { + // evaluated if it's not either 3 or 4 } -// As does `while`. -while (true){ - // An infinite loop! +// As does `while`. +while (true){ + // An infinite loop! } -// Do-while loops are like while loops, except they always run at least once. -var input; -do { - input = getInput(); -} while (!isValid(input)); +// Do-while loops are like while loops, except they always run at least once. +var input; +do { + input = getInput(); +} while (!isValid(input)); -// The `for` loop is the same as C and Java: -// initialization; continue condition; iteration. -for (var i = 0; i < 5; i++){ - // will run 5 times +// The `for` loop is the same as C and Java: +// initialization; continue condition; iteration. +for (var i = 0; i < 5; i++){ + // will run 5 times } -// Breaking out of labeled loops is similar to Java +// Breaking out of labeled loops is similar to Java outer: -for (var i = 0; i < 10; i++) { - for (var j = 0; j < 10; j++) { - if (i == 5 && j ==5) { - break outer; - // breaks out of outer loop instead of only the inner one - } - } +for (var i = 0; i < 10; i++) { + for (var j = 0; j < 10; j++) { + if (i == 5 && j ==5) { + break outer; + // breaks out of outer loop instead of only the inner one + } + } } -// The for/in statement allows iteration over properties of an object. -var description = ""; -var person = {fname:"Paul", lname:"Ken", age:18}; -for (var x in person){ - description += person[x] + " "; -} // description = 'Paul Ken 18 ' - -// The for/of statement allows iteration over iterable objects (including the built-in String,  -// Array, e.g. the Array-like arguments or NodeList objects, TypedArray, Map and Set,  -// and user-defined iterables). -var myPets = ""; -var pets = ["cat", "dog", "hamster", "hedgehog"]; -for (var pet of pets){ - myPets += pet + " "; -} // myPets = 'cat dog hamster hedgehog ' - -// && is logical and, || is logical or -if (house.size == "big" && house.colour == "blue"){ - house.contains = "bear"; +// The for/in statement allows iteration over properties of an object. +var description = ""; +var person = {fname:"Paul", lname:"Ken", age:18}; +for (var x in person){ + description += person[x] + " "; +} // description = 'Paul Ken 18 ' + +// The for/of statement allows iteration over iterable objects (including the built-in String,  +// Array, e.g. the Array-like arguments or NodeList objects, TypedArray, Map and Set,  +// and user-defined iterables). +var myPets = ""; +var pets = ["cat", "dog", "hamster", "hedgehog"]; +for (var pet of pets){ + myPets += pet + " "; +} // myPets = 'cat dog hamster hedgehog ' + +// && is logical and, || is logical or +if (house.size == "big" && house.colour == "blue"){ + house.contains = "bear"; } -if (colour == "red" || colour == "blue"){ - // colour is either red or blue +if (colour == "red" || colour == "blue"){ + // colour is either red or blue } -// && and || "short circuit", which is useful for setting default values. -var name = otherName || "default"; - -// The `switch` statement checks for equality with `===`. -// Use 'break' after each case -// or the cases after the correct one will be executed too. -grade = 'B'; -switch (grade) { - case 'A': - console.log("Great job"); - break; - case 'B': - console.log("OK job"); - break; - case 'C': - console.log("You can do better"); - break; - default: - console.log("Oy vey"); - break; +// && and || "short circuit", which is useful for setting default values. +var name = otherName || "default"; + +// The `switch` statement checks for equality with `===`. +// Use 'break' after each case +// or the cases after the correct one will be executed too. +grade = 'B'; +switch (grade) { + case 'A': + console.log("Great job"); + break; + case 'B': + console.log("OK job"); + break; + case 'C': + console.log("You can do better"); + break; + default: + console.log("Oy vey"); + break; } -/////////////////////////////////// -// 4. Functions, Scope and Closures +/////////////////////////////////// +// 4. Functions, Scope and Closures -// JavaScript functions are declared with the `function` keyword. -function myFunction(thing){ - return thing.toUpperCase(); +// JavaScript functions are declared with the `function` keyword. +function myFunction(thing){ + return thing.toUpperCase(); } -myFunction("foo"); // = "FOO" - -// Note that the value to be returned must start on the same line as the -// `return` keyword, otherwise you'll always return `undefined` due to -// automatic semicolon insertion. Watch out for this when using Allman style. -function myFunction(){ - return // <- semicolon automatically inserted here - {thisIsAn: 'object literal'}; +myFunction("foo"); // = "FOO" + +// Note that the value to be returned must start on the same line as the +// `return` keyword, otherwise you'll always return `undefined` due to +// automatic semicolon insertion. Watch out for this when using Allman style. +function myFunction(){ + return // <- semicolon automatically inserted here + {thisIsAn: 'object literal'}; } -myFunction(); // = undefined +myFunction(); // = undefined -// JavaScript functions are first class objects, so they can be reassigned to -// different variable names and passed to other functions as arguments - for -// example, when supplying an event handler: -function myFunction(){ - // this code will be called in 5 seconds' time +// JavaScript functions are first class objects, so they can be reassigned to +// different variable names and passed to other functions as arguments - for +// example, when supplying an event handler: +function myFunction(){ + // this code will be called in 5 seconds' time } -setTimeout(myFunction, 5000); -// Note: setTimeout isn't part of the JS language, but is provided by browsers -// and Node.js. +setTimeout(myFunction, 5000); +// Note: setTimeout isn't part of the JS language, but is provided by browsers +// and Node.js. -// Another function provided by browsers is setInterval -function myFunction(){ - // this code will be called every 5 seconds +// Another function provided by browsers is setInterval +function myFunction(){ + // this code will be called every 5 seconds } -setInterval(myFunction, 5000); +setInterval(myFunction, 5000); -// Function objects don't even have to be declared with a name - you can write -// an anonymous function definition directly into the arguments of another. +// Function objects don't even have to be declared with a name - you can write +// an anonymous function definition directly into the arguments of another. setTimeout(function(){ - // this code will be called in 5 seconds' time -}, 5000); + // this code will be called in 5 seconds' time +}, 5000); -// JavaScript has function scope; functions get their own scope but other blocks -// do not. -if (true){ - var i = 5; +// JavaScript has function scope; functions get their own scope but other blocks +// do not. +if (true){ + var i = 5; } -i; // = 5 - not undefined as you'd expect in a block-scoped language +i; // = 5 - not undefined as you'd expect in a block-scoped language -// This has led to a common pattern of "immediately-executing anonymous -// functions", which prevent temporary variables from leaking into the global -// scope. +// This has led to a common pattern of "immediately-executing anonymous +// functions", which prevent temporary variables from leaking into the global +// scope. (function(){ - var temporary = 5; - // We can access the global scope by assigning to the "global object", which - // in a web browser is always `window`. The global object may have a - // different name in non-browser environments such as Node.js. - window.permanent = 10; + var temporary = 5; + // We can access the global scope by assigning to the "global object", which + // in a web browser is always `window`. The global object may have a + // different name in non-browser environments such as Node.js. + window.permanent = 10; })(); -temporary; // raises ReferenceError -permanent; // = 10 - -// One of JavaScript's most powerful features is closures. If a function is -// defined inside another function, the inner function has access to all the -// outer function's variables, even after the outer function exits. -function sayHelloInFiveSeconds(name){ - var prompt = "Hello, " + name + "!"; - // Inner functions are put in the local scope by default, as if they were - // declared with `var`. - function inner(){ - alert(prompt); - } - setTimeout(inner, 5000); - // setTimeout is asynchronous, so the sayHelloInFiveSeconds function will - // exit immediately, and setTimeout will call inner afterwards. However, - // because inner is "closed over" sayHelloInFiveSeconds, inner still has - // access to the `prompt` variable when it is finally called. +temporary; // raises ReferenceError +permanent; // = 10 + +// One of JavaScript's most powerful features is closures. If a function is +// defined inside another function, the inner function has access to all the +// outer function's variables, even after the outer function exits. +function sayHelloInFiveSeconds(name){ + var prompt = "Hello, " + name + "!"; + // Inner functions are put in the local scope by default, as if they were + // declared with `var`. + function inner(){ + alert(prompt); + } + setTimeout(inner, 5000); + // setTimeout is asynchronous, so the sayHelloInFiveSeconds function will + // exit immediately, and setTimeout will call inner afterwards. However, + // because inner is "closed over" sayHelloInFiveSeconds, inner still has + // access to the `prompt` variable when it is finally called. } -sayHelloInFiveSeconds("Adam"); // will open a popup with "Hello, Adam!" in 5s +sayHelloInFiveSeconds("Adam"); // will open a popup with "Hello, Adam!" in 5s -/////////////////////////////////// -// 5. More about Objects; Constructors and Prototypes +/////////////////////////////////// +// 5. More about Objects; Constructors and Prototypes -// Objects can contain functions. -var myObj = { - myFunc: function(){ - return "Hello world!"; - } +// Objects can contain functions. +var myObj = { + myFunc: function(){ + return "Hello world!"; + } }; -myObj.myFunc(); // = "Hello world!" - -// When functions attached to an object are called, they can access the object -// they're attached to using the `this` keyword. -myObj = { - myString: "Hello world!", - myFunc: function(){ - return this.myString; - } +myObj.myFunc(); // = "Hello world!" + +// When functions attached to an object are called, they can access the object +// they're attached to using the `this` keyword. +myObj = { + myString: "Hello world!", + myFunc: function(){ + return this.myString; + } }; -myObj.myFunc(); // = "Hello world!" - -// What this is set to has to do with how the function is called, not where -// it's defined. So, our function doesn't work if it isn't called in the -// context of the object. -var myFunc = myObj.myFunc; -myFunc(); // = undefined - -// Inversely, a function can be assigned to the object and gain access to it -// through `this`, even if it wasn't attached when it was defined. -var myOtherFunc = function(){ - return this.myString.toUpperCase(); +myObj.myFunc(); // = "Hello world!" + +// What this is set to has to do with how the function is called, not where +// it's defined. So, our function doesn't work if it isn't called in the +// context of the object. +var myFunc = myObj.myFunc; +myFunc(); // = undefined + +// Inversely, a function can be assigned to the object and gain access to it +// through `this`, even if it wasn't attached when it was defined. +var myOtherFunc = function(){ + return this.myString.toUpperCase(); }; -myObj.myOtherFunc = myOtherFunc; -myObj.myOtherFunc(); // = "HELLO WORLD!" +myObj.myOtherFunc = myOtherFunc; +myObj.myOtherFunc(); // = "HELLO WORLD!" -// We can also specify a context for a function to execute in when we invoke it -// using `call` or `apply`. +// We can also specify a context for a function to execute in when we invoke it +// using `call` or `apply`. -var anotherFunc = function(s){ - return this.myString + s; +var anotherFunc = function(s){ + return this.myString + s; }; -anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" +anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" -// The `apply` function is nearly identical, but takes an array for an argument -// list. +// The `apply` function is nearly identical, but takes an array for an argument +// list. -anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" +anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" -// This is useful when working with a function that accepts a sequence of -// arguments and you want to pass an array. +// This is useful when working with a function that accepts a sequence of +// arguments and you want to pass an array. -Math.min(42, 6, 27); // = 6 -Math.min([42, 6, 27]); // = NaN (uh-oh!) -Math.min.apply(Math, [42, 6, 27]); // = 6 +Math.min(42, 6, 27); // = 6 +Math.min([42, 6, 27]); // = NaN (uh-oh!) +Math.min.apply(Math, [42, 6, 27]); // = 6 -// But, `call` and `apply` are only temporary. When we want it to stick, we can -// use `bind`. +// But, `call` and `apply` are only temporary. When we want it to stick, we can +// use `bind`. -var boundFunc = anotherFunc.bind(myObj); -boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" +var boundFunc = anotherFunc.bind(myObj); +boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" -// `bind` can also be used to partially apply (curry) a function. +// `bind` can also be used to partially apply (curry) a function. -var product = function(a, b){ return a * b; }; -var doubler = product.bind(this, 2); -doubler(8); // = 16 +var product = function(a, b){ return a * b; }; +var doubler = product.bind(this, 2); +doubler(8); // = 16 -// When you call a function with the `new` keyword, a new object is created, and -// made available to the function via the `this` keyword. Functions designed to be -// called like that are called constructors. +// When you call a function with the `new` keyword, a new object is created, and +// made available to the function via the `this` keyword. Functions designed to be +// called like that are called constructors. -var MyConstructor = function(){ - this.myNumber = 5; +var MyConstructor = function(){ + this.myNumber = 5; }; -myNewObj = new MyConstructor(); // = {myNumber: 5} -myNewObj.myNumber; // = 5 - -// Unlike most other popular object-oriented languages, JavaScript has no -// concept of 'instances' created from 'class' blueprints; instead, JavaScript -// combines instantiation and inheritance into a single concept: a 'prototype'. - -// Every JavaScript object has a 'prototype'. When you go to access a property -// on an object that doesn't exist on the actual object, the interpreter will -// look at its prototype. - -// Some JS implementations let you access an object's prototype on the magic -// property `__proto__`. While this is useful for explaining prototypes it's not -// part of the standard; we'll get to standard ways of using prototypes later. -var myObj = { - myString: "Hello world!" +myNewObj = new MyConstructor(); // = {myNumber: 5} +myNewObj.myNumber; // = 5 + +// Unlike most other popular object-oriented languages, JavaScript has no +// concept of 'instances' created from 'class' blueprints; instead, JavaScript +// combines instantiation and inheritance into a single concept: a 'prototype'. + +// Every JavaScript object has a 'prototype'. When you go to access a property +// on an object that doesn't exist on the actual object, the interpreter will +// look at its prototype. + +// Some JS implementations let you access an object's prototype on the magic +// property `__proto__`. While this is useful for explaining prototypes it's not +// part of the standard; we'll get to standard ways of using prototypes later. +var myObj = { + myString: "Hello world!" }; -var myPrototype = { - meaningOfLife: 42, - myFunc: function(){ - return this.myString.toLowerCase(); - } +var myPrototype = { + meaningOfLife: 42, + myFunc: function(){ + return this.myString.toLowerCase(); + } }; -myObj.__proto__ = myPrototype; -myObj.meaningOfLife; // = 42 +myObj.__proto__ = myPrototype; +myObj.meaningOfLife; // = 42 -// This works for functions, too. -myObj.myFunc(); // = "hello world!" +// This works for functions, too. +myObj.myFunc(); // = "hello world!" -// Of course, if your property isn't on your prototype, the prototype's -// prototype is searched, and so on. -myPrototype.__proto__ = { - myBoolean: true +// Of course, if your property isn't on your prototype, the prototype's +// prototype is searched, and so on. +myPrototype.__proto__ = { + myBoolean: true }; -myObj.myBoolean; // = true - -// There's no copying involved here; each object stores a reference to its -// prototype. This means we can alter the prototype and our changes will be -// reflected everywhere. -myPrototype.meaningOfLife = 43; -myObj.meaningOfLife; // = 43 - -// The for/in statement allows iteration over properties of an object, -// walking up the prototype chain until it sees a null prototype. -for (var x in myObj){ - console.log(myObj[x]); +myObj.myBoolean; // = true + +// There's no copying involved here; each object stores a reference to its +// prototype. This means we can alter the prototype and our changes will be +// reflected everywhere. +myPrototype.meaningOfLife = 43; +myObj.meaningOfLife; // = 43 + +// The for/in statement allows iteration over properties of an object, +// walking up the prototype chain until it sees a null prototype. +for (var x in myObj){ + console.log(myObj[x]); } -///prints: -// Hello world! -// 43 -// [Function: myFunc] -// true - -// To only consider properties attached to the object itself -// and not its prototypes, use the `hasOwnProperty()` check. -for (var x in myObj){ - if (myObj.hasOwnProperty(x)){ - console.log(myObj[x]); - } +///prints: +// Hello world! +// 43 +// [Function: myFunc] +// true + +// To only consider properties attached to the object itself +// and not its prototypes, use the `hasOwnProperty()` check. +for (var x in myObj){ + if (myObj.hasOwnProperty(x)){ + console.log(myObj[x]); + } } -///prints: -// Hello world! - -// We mentioned that `__proto__` was non-standard, and there's no standard way to -// change the prototype of an existing object. However, there are two ways to -// create a new object with a given prototype. - -// The first is Object.create, which is a recent addition to JS, and therefore -// not available in all implementations yet. -var myObj = Object.create(myPrototype); -myObj.meaningOfLife; // = 43 - -// The second way, which works anywhere, has to do with constructors. -// Constructors have a property called prototype. This is *not* the prototype of -// the constructor function itself; instead, it's the prototype that new objects -// are given when they're created with that constructor and the new keyword. -MyConstructor.prototype = { - myNumber: 5, - getMyNumber: function(){ - return this.myNumber; - } +///prints: +// Hello world! + +// We mentioned that `__proto__` was non-standard, and there's no standard way to +// change the prototype of an existing object. However, there are two ways to +// create a new object with a given prototype. + +// The first is Object.create, which is a recent addition to JS, and therefore +// not available in all implementations yet. +var myObj = Object.create(myPrototype); +myObj.meaningOfLife; // = 43 + +// The second way, which works anywhere, has to do with constructors. +// Constructors have a property called prototype. This is *not* the prototype of +// the constructor function itself; instead, it's the prototype that new objects +// are given when they're created with that constructor and the new keyword. +MyConstructor.prototype = { + myNumber: 5, + getMyNumber: function(){ + return this.myNumber; + } }; -var myNewObj2 = new MyConstructor(); -myNewObj2.getMyNumber(); // = 5 -myNewObj2.myNumber = 6; -myNewObj2.getMyNumber(); // = 6 - -// Built-in types like strings and numbers also have constructors that create -// equivalent wrapper objects. -var myNumber = 12; -var myNumberObj = new Number(12); -myNumber == myNumberObj; // = true - -// Except, they aren't exactly equivalent. -typeof myNumber; // = 'number' -typeof myNumberObj; // = 'object' -myNumber === myNumberObj; // = false -if (0){ - // This code won't execute, because 0 is falsy. +var myNewObj2 = new MyConstructor(); +myNewObj2.getMyNumber(); // = 5 +myNewObj2.myNumber = 6; +myNewObj2.getMyNumber(); // = 6 + +// Built-in types like strings and numbers also have constructors that create +// equivalent wrapper objects. +var myNumber = 12; +var myNumberObj = new Number(12); +myNumber == myNumberObj; // = true + +// Except, they aren't exactly equivalent. +typeof myNumber; // = 'number' +typeof myNumberObj; // = 'object' +myNumber === myNumberObj; // = false +if (0){ + // This code won't execute, because 0 is falsy. } -if (new Number(0)){ - // This code will execute, because wrapped numbers are objects, and objects - // are always truthy. +if (new Number(0)){ + // This code will execute, because wrapped numbers are objects, and objects + // are always truthy. } -// However, the wrapper objects and the regular builtins share a prototype, so -// you can actually add functionality to a string, for instance. -String.prototype.firstCharacter = function(){ - return this.charAt(0); +// However, the wrapper objects and the regular builtins share a prototype, so +// you can actually add functionality to a string, for instance. +String.prototype.firstCharacter = function(){ + return this.charAt(0); }; -"abc".firstCharacter(); // = "a" - -// This fact is often used in "polyfilling", which is implementing newer -// features of JavaScript in an older subset of JavaScript, so that they can be -// used in older environments such as outdated browsers. - -// For instance, we mentioned that Object.create isn't yet available in all -// implementations, but we can still use it with this polyfill: -if (Object.create === undefined){ // don't overwrite it if it exists - Object.create = function(proto){ - // make a temporary constructor with the right prototype - var Constructor = function(){}; - Constructor.prototype = proto; - // then use it to create a new, appropriately-prototyped object - return new Constructor(); - }; +"abc".firstCharacter(); // = "a" + +// This fact is often used in "polyfilling", which is implementing newer +// features of JavaScript in an older subset of JavaScript, so that they can be +// used in older environments such as outdated browsers. + +// For instance, we mentioned that Object.create isn't yet available in all +// implementations, but we can still use it with this polyfill: +if (Object.create === undefined){ // don't overwrite it if it exists + Object.create = function(proto){ + // make a temporary constructor with the right prototype + var Constructor = function(){}; + Constructor.prototype = proto; + // then use it to create a new, appropriately-prototyped object + return new Constructor(); + }; } -// ES6 Additions +// ES6 Additions -// The "let" keyword allows you to define variables in a lexical scope,  -// as opposed to a block scope like the var keyword does. -let name = "Billy"; +// The "let" keyword allows you to define variables in a lexical scope,  +// as opposed to a function scope like the var keyword does. +let name = "Billy"; -// Variables defined with let can be reassigned new values. -name = "William"; +// Variables defined with let can be reassigned new values. +name = "William"; -// The "const" keyword allows you to define a variable in a lexical scope -// like with let, but you cannot reassign the value once one has been assigned. +// The "const" keyword allows you to define a variable in a lexical scope +// like with let, but you cannot reassign the value once one has been assigned. -const pi = 3.14; +const pi = 3.14; -pi = 4.13; // You cannot do this. +pi = 4.13; // You cannot do this. -// There is a new syntax for functions in ES6 known as "lambda syntax". -// This allows functions to be defined in a lexical scope like with variables -// defined by const and let.  +// There is a new syntax for functions in ES6 known as "lambda syntax". +// This allows functions to be defined in a lexical scope like with variables +// defined by const and let.  -const isEven = (number) => { - return number % 2 === 0; +const isEven = (number) => { + return number % 2 === 0; }; -isEven(7); // false +isEven(7); // false -// The "equivalent" of this function in the traditional syntax would look like this: +// The "equivalent" of this function in the traditional syntax would look like this: -function isEven(number) { - return number % 2 === 0; +function isEven(number) { + return number % 2 === 0; }; -// I put the word "equivalent" in double quotes because a function defined -// using the lambda syntax cannnot be called before the definition. -// The following is an example of invalid usage: +// I put the word "equivalent" in double quotes because a function defined +// using the lambda syntax cannot be called before the definition. +// The following is an example of invalid usage: -add(1, 8); +add(1, 8); -const add = (firstNumber, secondNumber) => { - return firstNumber + secondNumber; +const add = (firstNumber, secondNumber) => { + return firstNumber + secondNumber; }; diff --git a/tests/results/22 b/tests/results/22 index bfd13d39..6dd970d0 100644 --- a/tests/results/22 +++ b/tests/results/22 @@ -1,606 +1,606 @@ -// Single-line comments start with two slashes. -/* Multiline comments start with slash-star, - and end with star-slash */ +// Single-line comments start with two slashes. +/* Multiline comments start with slash-star, + and end with star-slash */ -// Statements can be terminated by ; +// Statements can be terminated by ; doStuff(); -// ... but they don't have to be, as semicolons are automatically inserted -// wherever there's a newline, except in certain cases. +// ... but they don't have to be, as semicolons are automatically inserted +// wherever there's a newline, except in certain cases. doStuff() -// Because those cases can cause unexpected results, we'll keep on using -// semicolons in this guide. +// Because those cases can cause unexpected results, we'll keep on using +// semicolons in this guide. -/////////////////////////////////// -// 1. Numbers, Strings and Operators +/////////////////////////////////// +// 1. Numbers, Strings and Operators -// JavaScript has one number type (which is a 64-bit IEEE 754 double). -// Doubles have a 52-bit mantissa, which is enough to store integers -// up to about 9✕10¹⁵ precisely. -3; // = 3 -1.5; // = 1.5 +// JavaScript has one number type (which is a 64-bit IEEE 754 double). +// Doubles have a 52-bit mantissa, which is enough to store integers +// up to about 9✕10¹⁵ precisely. +3; // = 3 +1.5; // = 1.5 -// Some basic arithmetic works as you'd expect. -1 + 1; // = 2 -0.1 + 0.2; // = 0.30000000000000004 -8 - 1; // = 7 -10 * 2; // = 20 -35 / 5; // = 7 +// Some basic arithmetic works as you'd expect. +1 + 1; // = 2 +0.1 + 0.2; // = 0.30000000000000004 +8 - 1; // = 7 +10 * 2; // = 20 +35 / 5; // = 7 -// Including uneven division. -5 / 2; // = 2.5 +// Including uneven division. +5 / 2; // = 2.5 -// And modulo division. -10 % 2; // = 0 -30 % 4; // = 2 -18.5 % 7; // = 4.5 +// And modulo division. +10 % 2; // = 0 +30 % 4; // = 2 +18.5 % 7; // = 4.5 -// Bitwise operations also work; when you perform a bitwise operation your float -// is converted to a signed int *up to* 32 bits. -1 << 2; // = 4 +// Bitwise operations also work; when you perform a bitwise operation your float +// is converted to a signed int *up to* 32 bits. +1 << 2; // = 4 -// Precedence is enforced with parentheses. -(1 + 3) * 2; // = 8 +// Precedence is enforced with parentheses. +(1 + 3) * 2; // = 8 -// There are three special not-a-real-number values: -Infinity; // result of e.g. 1/0 --Infinity; // result of e.g. -1/0 -NaN; // result of e.g. 0/0, stands for 'Not a Number' +// There are three special not-a-real-number values: +Infinity; // result of e.g. 1/0 +-Infinity; // result of e.g. -1/0 +NaN; // result of e.g. 0/0, stands for 'Not a Number' -// There's also a boolean type. +// There's also a boolean type. true; false; -// Strings are created with ' or ". +// Strings are created with ' or ". 'abc'; "Hello, world"; -// Negation uses the ! symbol -!true; // = false -!false; // = true +// Negation uses the ! symbol +!true; // = false +!false; // = true -// Equality is === -1 === 1; // = true -2 === 1; // = false +// Equality is === +1 === 1; // = true +2 === 1; // = false -// Inequality is !== -1 !== 1; // = false -2 !== 1; // = true +// Inequality is !== +1 !== 1; // = false +2 !== 1; // = true -// More comparisons -1 < 10; // = true -1 > 10; // = false -2 <= 2; // = true -2 >= 2; // = true +// More comparisons +1 < 10; // = true +1 > 10; // = false +2 <= 2; // = true +2 >= 2; // = true -// Strings are concatenated with + -"Hello " + "world!"; // = "Hello world!" +// Strings are concatenated with + +"Hello " + "world!"; // = "Hello world!" -// ... which works with more than just strings -"1, 2, " + 3; // = "1, 2, 3" -"Hello " + ["world", "!"]; // = "Hello world,!" +// ... which works with more than just strings +"1, 2, " + 3; // = "1, 2, 3" +"Hello " + ["world", "!"]; // = "Hello world,!" -// and are compared with < and > -"a" < "b"; // = true +// and are compared with < and > +"a" < "b"; // = true -// Type coercion is performed for comparisons with double equals... -"5" == 5; // = true -null == undefined; // = true +// Type coercion is performed for comparisons with double equals... +"5" == 5; // = true +null == undefined; // = true -// ...unless you use === -"5" === 5; // = false -null === undefined; // = false +// ...unless you use === +"5" === 5; // = false +null === undefined; // = false -// ...which can result in some weird behaviour... -13 + !0; // 14 -"13" + !0; // '13true' +// ...which can result in some weird behaviour... +13 + !0; // 14 +"13" + !0; // '13true' -// You can access characters in a string with `charAt` -"This is a string".charAt(0); // = 'T' +// You can access characters in a string with `charAt` +"This is a string".charAt(0); // = 'T' -// ...or use `substring` to get larger pieces. -"Hello world".substring(0, 5); // = "Hello" +// ...or use `substring` to get larger pieces. +"Hello world".substring(0, 5); // = "Hello" -// `length` is a property, so don't use (). -"Hello".length; // = 5 +// `length` is a property, so don't use (). +"Hello".length; // = 5 -// There's also `null` and `undefined`. -null; // used to indicate a deliberate non-value -undefined; // used to indicate a value is not currently present (although - // `undefined` is actually a value itself) +// There's also `null` and `undefined`. +null; // used to indicate a deliberate non-value +undefined; // used to indicate a value is not currently present (although + // `undefined` is actually a value itself) -// false, null, undefined, NaN, 0 and "" are falsy; everything else is truthy. -// Note that 0 is falsy and "0" is truthy, even though 0 == "0". +// false, null, undefined, NaN, 0 and "" are falsy; everything else is truthy. +// Note that 0 is falsy and "0" is truthy, even though 0 == "0". -/////////////////////////////////// -// 2. Variables, Arrays and Objects +/////////////////////////////////// +// 2. Variables, Arrays and Objects -// Variables are declared with the `var` keyword. JavaScript is dynamically -// typed, so you don't need to specify type. Assignment uses a single `=` -// character. -var someVar = 5; +// Variables are declared with the `var` keyword. JavaScript is dynamically +// typed, so you don't need to specify type. Assignment uses a single `=` +// character. +var someVar = 5; -// If you leave the var keyword off, you won't get an error... -someOtherVar = 10; +// If you leave the var keyword off, you won't get an error... +someOtherVar = 10; -// ...but your variable will be created in the global scope, not in the scope -// you defined it in. +// ...but your variable will be created in the global scope, not in the scope +// you defined it in. -// Variables declared without being assigned to are set to undefined. -var someThirdVar; // = undefined +// Variables declared without being assigned to are set to undefined. +var someThirdVar; // = undefined -// If you want to declare a couple of variables, then you could use a comma -// separator -var someFourthVar = 2, someFifthVar = 4; +// If you want to declare a couple of variables, then you could use a comma +// separator +var someFourthVar = 2, someFifthVar = 4; -// There's shorthand for performing math operations on variables: -someVar += 5; // equivalent to someVar = someVar + 5; someVar is 10 now -someVar *= 10; // now someVar is 100 +// There's shorthand for performing math operations on variables: +someVar += 5; // equivalent to someVar = someVar + 5; someVar is 10 now +someVar *= 10; // now someVar is 100 -// and an even-shorter-hand for adding or subtracting 1 -someVar++; // now someVar is 101 -someVar--; // back to 100 +// and an even-shorter-hand for adding or subtracting 1 +someVar++; // now someVar is 101 +someVar--; // back to 100 -// Arrays are ordered lists of values, of any type. -var myArray = ["Hello", 45, true]; +// Arrays are ordered lists of values, of any type. +var myArray = ["Hello", 45, true]; -// Their members can be accessed using the square-brackets subscript syntax. -// Array indices start at zero. -myArray[1]; // = 45 +// Their members can be accessed using the square-brackets subscript syntax. +// Array indices start at zero. +myArray[1]; // = 45 -// Arrays are mutable and of variable length. +// Arrays are mutable and of variable length. myArray.push("World"); -myArray.length; // = 4 +myArray.length; // = 4 -// Add/Modify at specific index -myArray[3] = "Hello"; +// Add/Modify at specific index +myArray[3] = "Hello"; -// Add and remove element from front or back end of an array -myArray.unshift(3); // Add as the first element -someVar = myArray.shift(); // Remove first element and return it -myArray.push(3); // Add as the last element -someVar = myArray.pop(); // Remove last element and return it +// Add and remove element from front or back end of an array +myArray.unshift(3); // Add as the first element +someVar = myArray.shift(); // Remove first element and return it +myArray.push(3); // Add as the last element +someVar = myArray.pop(); // Remove last element and return it -// Join all elements of an array with semicolon -var myArray0 = [32,false,"js",12,56,90]; -myArray0.join(";"); // = "32;false;js;12;56;90" +// Join all elements of an array with semicolon +var myArray0 = [32,false,"js",12,56,90]; +myArray0.join(";"); // = "32;false;js;12;56;90" -// Get subarray of elements from index 1 (include) to 4 (exclude) -myArray0.slice(1,4); // = [false,"js",12] +// Get subarray of elements from index 1 (include) to 4 (exclude) +myArray0.slice(1,4); // = [false,"js",12] -// Remove 4 elements starting from index 2, and insert there strings -// "hi","wr" and "ld"; return removed subarray -myArray0.splice(2,4,"hi","wr","ld"); // = ["js",12,56,90] -// myArray0 === [32,false,"hi","wr","ld"] +// Remove 4 elements starting from index 2, and insert there strings +// "hi","wr" and "ld"; return removed subarray +myArray0.splice(2,4,"hi","wr","ld"); // = ["js",12,56,90] +// myArray0 === [32,false,"hi","wr","ld"] -// JavaScript's objects are equivalent to "dictionaries" or "maps" in other -// languages: an unordered collection of key-value pairs. -var myObj = {key1: "Hello", key2: "World"}; +// JavaScript's objects are equivalent to "dictionaries" or "maps" in other +// languages: an unordered collection of key-value pairs. +var myObj = {key1: "Hello", key2: "World"}; -// Keys are strings, but quotes aren't required if they're a valid -// JavaScript identifier. Values can be any type. -var myObj = {myKey: "myValue", "my other key": 4}; +// Keys are strings, but quotes aren't required if they're a valid +// JavaScript identifier. Values can be any type. +var myObj = {myKey: "myValue", "my other key": 4}; -// Object attributes can also be accessed using the subscript syntax, -myObj["my other key"]; // = 4 +// Object attributes can also be accessed using the subscript syntax, +myObj["my other key"]; // = 4 -// ... or using the dot syntax, provided the key is a valid identifier. -myObj.myKey; // = "myValue" +// ... or using the dot syntax, provided the key is a valid identifier. +myObj.myKey; // = "myValue" -// Objects are mutable; values can be changed and new keys added. -myObj.myThirdKey = true; +// Objects are mutable; values can be changed and new keys added. +myObj.myThirdKey = true; -// If you try to access a value that's not yet set, you'll get undefined. -myObj.myFourthKey; // = undefined +// If you try to access a value that's not yet set, you'll get undefined. +myObj.myFourthKey; // = undefined -/////////////////////////////////// -// 3. Logic and Control Structures +/////////////////////////////////// +// 3. Logic and Control Structures -// The `if` structure works as you'd expect. -var count = 1; -if (count == 3){ - // evaluated if count is 3 -} else if (count == 4){ - // evaluated if count is 4 -} else { - // evaluated if it's not either 3 or 4 +// The `if` structure works as you'd expect. +var count = 1; +if (count == 3){ + // evaluated if count is 3 +} else if (count == 4){ + // evaluated if count is 4 +} else { + // evaluated if it's not either 3 or 4 } -// As does `while`. -while (true){ - // An infinite loop! +// As does `while`. +while (true){ + // An infinite loop! } -// Do-while loops are like while loops, except they always run at least once. -var input; -do { - input = getInput(); -} while (!isValid(input)); +// Do-while loops are like while loops, except they always run at least once. +var input; +do { + input = getInput(); +} while (!isValid(input)); -// The `for` loop is the same as C and Java: -// initialization; continue condition; iteration. -for (var i = 0; i < 5; i++){ - // will run 5 times +// The `for` loop is the same as C and Java: +// initialization; continue condition; iteration. +for (var i = 0; i < 5; i++){ + // will run 5 times } -// Breaking out of labeled loops is similar to Java +// Breaking out of labeled loops is similar to Java outer: -for (var i = 0; i < 10; i++) { - for (var j = 0; j < 10; j++) { - if (i == 5 && j ==5) { - break outer; - // breaks out of outer loop instead of only the inner one - } - } +for (var i = 0; i < 10; i++) { + for (var j = 0; j < 10; j++) { + if (i == 5 && j ==5) { + break outer; + // breaks out of outer loop instead of only the inner one + } + } } -// The for/in statement allows iteration over properties of an object. -var description = ""; -var person = {fname:"Paul", lname:"Ken", age:18}; -for (var x in person){ - description += person[x] + " "; -} // description = 'Paul Ken 18 ' - -// The for/of statement allows iteration over iterable objects (including the built-in String,  -// Array, e.g. the Array-like arguments or NodeList objects, TypedArray, Map and Set,  -// and user-defined iterables). -var myPets = ""; -var pets = ["cat", "dog", "hamster", "hedgehog"]; -for (var pet of pets){ - myPets += pet + " "; -} // myPets = 'cat dog hamster hedgehog ' - -// && is logical and, || is logical or -if (house.size == "big" && house.colour == "blue"){ - house.contains = "bear"; +// The for/in statement allows iteration over properties of an object. +var description = ""; +var person = {fname:"Paul", lname:"Ken", age:18}; +for (var x in person){ + description += person[x] + " "; +} // description = 'Paul Ken 18 ' + +// The for/of statement allows iteration over iterable objects (including the built-in String,  +// Array, e.g. the Array-like arguments or NodeList objects, TypedArray, Map and Set,  +// and user-defined iterables). +var myPets = ""; +var pets = ["cat", "dog", "hamster", "hedgehog"]; +for (var pet of pets){ + myPets += pet + " "; +} // myPets = 'cat dog hamster hedgehog ' + +// && is logical and, || is logical or +if (house.size == "big" && house.colour == "blue"){ + house.contains = "bear"; } -if (colour == "red" || colour == "blue"){ - // colour is either red or blue +if (colour == "red" || colour == "blue"){ + // colour is either red or blue } -// && and || "short circuit", which is useful for setting default values. -var name = otherName || "default"; - -// The `switch` statement checks for equality with `===`. -// Use 'break' after each case -// or the cases after the correct one will be executed too. -grade = 'B'; -switch (grade) { - case 'A': - console.log("Great job"); - break; - case 'B': - console.log("OK job"); - break; - case 'C': - console.log("You can do better"); - break; - default: - console.log("Oy vey"); - break; +// && and || "short circuit", which is useful for setting default values. +var name = otherName || "default"; + +// The `switch` statement checks for equality with `===`. +// Use 'break' after each case +// or the cases after the correct one will be executed too. +grade = 'B'; +switch (grade) { + case 'A': + console.log("Great job"); + break; + case 'B': + console.log("OK job"); + break; + case 'C': + console.log("You can do better"); + break; + default: + console.log("Oy vey"); + break; } -/////////////////////////////////// -// 4. Functions, Scope and Closures +/////////////////////////////////// +// 4. Functions, Scope and Closures -// JavaScript functions are declared with the `function` keyword. -function myFunction(thing){ - return thing.toUpperCase(); +// JavaScript functions are declared with the `function` keyword. +function myFunction(thing){ + return thing.toUpperCase(); } -myFunction("foo"); // = "FOO" - -// Note that the value to be returned must start on the same line as the -// `return` keyword, otherwise you'll always return `undefined` due to -// automatic semicolon insertion. Watch out for this when using Allman style. -function myFunction(){ - return // <- semicolon automatically inserted here - {thisIsAn: 'object literal'}; +myFunction("foo"); // = "FOO" + +// Note that the value to be returned must start on the same line as the +// `return` keyword, otherwise you'll always return `undefined` due to +// automatic semicolon insertion. Watch out for this when using Allman style. +function myFunction(){ + return // <- semicolon automatically inserted here + {thisIsAn: 'object literal'}; } -myFunction(); // = undefined +myFunction(); // = undefined -// JavaScript functions are first class objects, so they can be reassigned to -// different variable names and passed to other functions as arguments - for -// example, when supplying an event handler: -function myFunction(){ - // this code will be called in 5 seconds' time +// JavaScript functions are first class objects, so they can be reassigned to +// different variable names and passed to other functions as arguments - for +// example, when supplying an event handler: +function myFunction(){ + // this code will be called in 5 seconds' time } -setTimeout(myFunction, 5000); -// Note: setTimeout isn't part of the JS language, but is provided by browsers -// and Node.js. +setTimeout(myFunction, 5000); +// Note: setTimeout isn't part of the JS language, but is provided by browsers +// and Node.js. -// Another function provided by browsers is setInterval -function myFunction(){ - // this code will be called every 5 seconds +// Another function provided by browsers is setInterval +function myFunction(){ + // this code will be called every 5 seconds } -setInterval(myFunction, 5000); +setInterval(myFunction, 5000); -// Function objects don't even have to be declared with a name - you can write -// an anonymous function definition directly into the arguments of another. +// Function objects don't even have to be declared with a name - you can write +// an anonymous function definition directly into the arguments of another. setTimeout(function(){ - // this code will be called in 5 seconds' time -}, 5000); + // this code will be called in 5 seconds' time +}, 5000); -// JavaScript has function scope; functions get their own scope but other blocks -// do not. -if (true){ - var i = 5; +// JavaScript has function scope; functions get their own scope but other blocks +// do not. +if (true){ + var i = 5; } -i; // = 5 - not undefined as you'd expect in a block-scoped language +i; // = 5 - not undefined as you'd expect in a block-scoped language -// This has led to a common pattern of "immediately-executing anonymous -// functions", which prevent temporary variables from leaking into the global -// scope. +// This has led to a common pattern of "immediately-executing anonymous +// functions", which prevent temporary variables from leaking into the global +// scope. (function(){ - var temporary = 5; - // We can access the global scope by assigning to the "global object", which - // in a web browser is always `window`. The global object may have a - // different name in non-browser environments such as Node.js. - window.permanent = 10; + var temporary = 5; + // We can access the global scope by assigning to the "global object", which + // in a web browser is always `window`. The global object may have a + // different name in non-browser environments such as Node.js. + window.permanent = 10; })(); -temporary; // raises ReferenceError -permanent; // = 10 - -// One of JavaScript's most powerful features is closures. If a function is -// defined inside another function, the inner function has access to all the -// outer function's variables, even after the outer function exits. -function sayHelloInFiveSeconds(name){ - var prompt = "Hello, " + name + "!"; - // Inner functions are put in the local scope by default, as if they were - // declared with `var`. - function inner(){ - alert(prompt); - } - setTimeout(inner, 5000); - // setTimeout is asynchronous, so the sayHelloInFiveSeconds function will - // exit immediately, and setTimeout will call inner afterwards. However, - // because inner is "closed over" sayHelloInFiveSeconds, inner still has - // access to the `prompt` variable when it is finally called. +temporary; // raises ReferenceError +permanent; // = 10 + +// One of JavaScript's most powerful features is closures. If a function is +// defined inside another function, the inner function has access to all the +// outer function's variables, even after the outer function exits. +function sayHelloInFiveSeconds(name){ + var prompt = "Hello, " + name + "!"; + // Inner functions are put in the local scope by default, as if they were + // declared with `var`. + function inner(){ + alert(prompt); + } + setTimeout(inner, 5000); + // setTimeout is asynchronous, so the sayHelloInFiveSeconds function will + // exit immediately, and setTimeout will call inner afterwards. However, + // because inner is "closed over" sayHelloInFiveSeconds, inner still has + // access to the `prompt` variable when it is finally called. } -sayHelloInFiveSeconds("Adam"); // will open a popup with "Hello, Adam!" in 5s +sayHelloInFiveSeconds("Adam"); // will open a popup with "Hello, Adam!" in 5s -/////////////////////////////////// -// 5. More about Objects; Constructors and Prototypes +/////////////////////////////////// +// 5. More about Objects; Constructors and Prototypes -// Objects can contain functions. -var myObj = { - myFunc: function(){ - return "Hello world!"; - } +// Objects can contain functions. +var myObj = { + myFunc: function(){ + return "Hello world!"; + } }; -myObj.myFunc(); // = "Hello world!" - -// When functions attached to an object are called, they can access the object -// they're attached to using the `this` keyword. -myObj = { - myString: "Hello world!", - myFunc: function(){ - return this.myString; - } +myObj.myFunc(); // = "Hello world!" + +// When functions attached to an object are called, they can access the object +// they're attached to using the `this` keyword. +myObj = { + myString: "Hello world!", + myFunc: function(){ + return this.myString; + } }; -myObj.myFunc(); // = "Hello world!" - -// What this is set to has to do with how the function is called, not where -// it's defined. So, our function doesn't work if it isn't called in the -// context of the object. -var myFunc = myObj.myFunc; -myFunc(); // = undefined - -// Inversely, a function can be assigned to the object and gain access to it -// through `this`, even if it wasn't attached when it was defined. -var myOtherFunc = function(){ - return this.myString.toUpperCase(); +myObj.myFunc(); // = "Hello world!" + +// What this is set to has to do with how the function is called, not where +// it's defined. So, our function doesn't work if it isn't called in the +// context of the object. +var myFunc = myObj.myFunc; +myFunc(); // = undefined + +// Inversely, a function can be assigned to the object and gain access to it +// through `this`, even if it wasn't attached when it was defined. +var myOtherFunc = function(){ + return this.myString.toUpperCase(); }; -myObj.myOtherFunc = myOtherFunc; -myObj.myOtherFunc(); // = "HELLO WORLD!" +myObj.myOtherFunc = myOtherFunc; +myObj.myOtherFunc(); // = "HELLO WORLD!" -// We can also specify a context for a function to execute in when we invoke it -// using `call` or `apply`. +// We can also specify a context for a function to execute in when we invoke it +// using `call` or `apply`. -var anotherFunc = function(s){ - return this.myString + s; +var anotherFunc = function(s){ + return this.myString + s; }; -anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" +anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" -// The `apply` function is nearly identical, but takes an array for an argument -// list. +// The `apply` function is nearly identical, but takes an array for an argument +// list. -anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" +anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" -// This is useful when working with a function that accepts a sequence of -// arguments and you want to pass an array. +// This is useful when working with a function that accepts a sequence of +// arguments and you want to pass an array. -Math.min(42, 6, 27); // = 6 -Math.min([42, 6, 27]); // = NaN (uh-oh!) -Math.min.apply(Math, [42, 6, 27]); // = 6 +Math.min(42, 6, 27); // = 6 +Math.min([42, 6, 27]); // = NaN (uh-oh!) +Math.min.apply(Math, [42, 6, 27]); // = 6 -// But, `call` and `apply` are only temporary. When we want it to stick, we can -// use `bind`. +// But, `call` and `apply` are only temporary. When we want it to stick, we can +// use `bind`. -var boundFunc = anotherFunc.bind(myObj); -boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" +var boundFunc = anotherFunc.bind(myObj); +boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" -// `bind` can also be used to partially apply (curry) a function. +// `bind` can also be used to partially apply (curry) a function. -var product = function(a, b){ return a * b; }; -var doubler = product.bind(this, 2); -doubler(8); // = 16 +var product = function(a, b){ return a * b; }; +var doubler = product.bind(this, 2); +doubler(8); // = 16 -// When you call a function with the `new` keyword, a new object is created, and -// made available to the function via the `this` keyword. Functions designed to be -// called like that are called constructors. +// When you call a function with the `new` keyword, a new object is created, and +// made available to the function via the `this` keyword. Functions designed to be +// called like that are called constructors. -var MyConstructor = function(){ - this.myNumber = 5; +var MyConstructor = function(){ + this.myNumber = 5; }; -myNewObj = new MyConstructor(); // = {myNumber: 5} -myNewObj.myNumber; // = 5 - -// Unlike most other popular object-oriented languages, JavaScript has no -// concept of 'instances' created from 'class' blueprints; instead, JavaScript -// combines instantiation and inheritance into a single concept: a 'prototype'. - -// Every JavaScript object has a 'prototype'. When you go to access a property -// on an object that doesn't exist on the actual object, the interpreter will -// look at its prototype. - -// Some JS implementations let you access an object's prototype on the magic -// property `__proto__`. While this is useful for explaining prototypes it's not -// part of the standard; we'll get to standard ways of using prototypes later. -var myObj = { - myString: "Hello world!" +myNewObj = new MyConstructor(); // = {myNumber: 5} +myNewObj.myNumber; // = 5 + +// Unlike most other popular object-oriented languages, JavaScript has no +// concept of 'instances' created from 'class' blueprints; instead, JavaScript +// combines instantiation and inheritance into a single concept: a 'prototype'. + +// Every JavaScript object has a 'prototype'. When you go to access a property +// on an object that doesn't exist on the actual object, the interpreter will +// look at its prototype. + +// Some JS implementations let you access an object's prototype on the magic +// property `__proto__`. While this is useful for explaining prototypes it's not +// part of the standard; we'll get to standard ways of using prototypes later. +var myObj = { + myString: "Hello world!" }; -var myPrototype = { - meaningOfLife: 42, - myFunc: function(){ - return this.myString.toLowerCase(); - } +var myPrototype = { + meaningOfLife: 42, + myFunc: function(){ + return this.myString.toLowerCase(); + } }; -myObj.__proto__ = myPrototype; -myObj.meaningOfLife; // = 42 +myObj.__proto__ = myPrototype; +myObj.meaningOfLife; // = 42 -// This works for functions, too. -myObj.myFunc(); // = "hello world!" +// This works for functions, too. +myObj.myFunc(); // = "hello world!" -// Of course, if your property isn't on your prototype, the prototype's -// prototype is searched, and so on. -myPrototype.__proto__ = { - myBoolean: true +// Of course, if your property isn't on your prototype, the prototype's +// prototype is searched, and so on. +myPrototype.__proto__ = { + myBoolean: true }; -myObj.myBoolean; // = true - -// There's no copying involved here; each object stores a reference to its -// prototype. This means we can alter the prototype and our changes will be -// reflected everywhere. -myPrototype.meaningOfLife = 43; -myObj.meaningOfLife; // = 43 - -// The for/in statement allows iteration over properties of an object, -// walking up the prototype chain until it sees a null prototype. -for (var x in myObj){ - console.log(myObj[x]); +myObj.myBoolean; // = true + +// There's no copying involved here; each object stores a reference to its +// prototype. This means we can alter the prototype and our changes will be +// reflected everywhere. +myPrototype.meaningOfLife = 43; +myObj.meaningOfLife; // = 43 + +// The for/in statement allows iteration over properties of an object, +// walking up the prototype chain until it sees a null prototype. +for (var x in myObj){ + console.log(myObj[x]); } -///prints: -// Hello world! -// 43 -// [Function: myFunc] -// true - -// To only consider properties attached to the object itself -// and not its prototypes, use the `hasOwnProperty()` check. -for (var x in myObj){ - if (myObj.hasOwnProperty(x)){ - console.log(myObj[x]); - } +///prints: +// Hello world! +// 43 +// [Function: myFunc] +// true + +// To only consider properties attached to the object itself +// and not its prototypes, use the `hasOwnProperty()` check. +for (var x in myObj){ + if (myObj.hasOwnProperty(x)){ + console.log(myObj[x]); + } } -///prints: -// Hello world! - -// We mentioned that `__proto__` was non-standard, and there's no standard way to -// change the prototype of an existing object. However, there are two ways to -// create a new object with a given prototype. - -// The first is Object.create, which is a recent addition to JS, and therefore -// not available in all implementations yet. -var myObj = Object.create(myPrototype); -myObj.meaningOfLife; // = 43 - -// The second way, which works anywhere, has to do with constructors. -// Constructors have a property called prototype. This is *not* the prototype of -// the constructor function itself; instead, it's the prototype that new objects -// are given when they're created with that constructor and the new keyword. -MyConstructor.prototype = { - myNumber: 5, - getMyNumber: function(){ - return this.myNumber; - } +///prints: +// Hello world! + +// We mentioned that `__proto__` was non-standard, and there's no standard way to +// change the prototype of an existing object. However, there are two ways to +// create a new object with a given prototype. + +// The first is Object.create, which is a recent addition to JS, and therefore +// not available in all implementations yet. +var myObj = Object.create(myPrototype); +myObj.meaningOfLife; // = 43 + +// The second way, which works anywhere, has to do with constructors. +// Constructors have a property called prototype. This is *not* the prototype of +// the constructor function itself; instead, it's the prototype that new objects +// are given when they're created with that constructor and the new keyword. +MyConstructor.prototype = { + myNumber: 5, + getMyNumber: function(){ + return this.myNumber; + } }; -var myNewObj2 = new MyConstructor(); -myNewObj2.getMyNumber(); // = 5 -myNewObj2.myNumber = 6; -myNewObj2.getMyNumber(); // = 6 - -// Built-in types like strings and numbers also have constructors that create -// equivalent wrapper objects. -var myNumber = 12; -var myNumberObj = new Number(12); -myNumber == myNumberObj; // = true - -// Except, they aren't exactly equivalent. -typeof myNumber; // = 'number' -typeof myNumberObj; // = 'object' -myNumber === myNumberObj; // = false -if (0){ - // This code won't execute, because 0 is falsy. +var myNewObj2 = new MyConstructor(); +myNewObj2.getMyNumber(); // = 5 +myNewObj2.myNumber = 6; +myNewObj2.getMyNumber(); // = 6 + +// Built-in types like strings and numbers also have constructors that create +// equivalent wrapper objects. +var myNumber = 12; +var myNumberObj = new Number(12); +myNumber == myNumberObj; // = true + +// Except, they aren't exactly equivalent. +typeof myNumber; // = 'number' +typeof myNumberObj; // = 'object' +myNumber === myNumberObj; // = false +if (0){ + // This code won't execute, because 0 is falsy. } -if (new Number(0)){ - // This code will execute, because wrapped numbers are objects, and objects - // are always truthy. +if (new Number(0)){ + // This code will execute, because wrapped numbers are objects, and objects + // are always truthy. } -// However, the wrapper objects and the regular builtins share a prototype, so -// you can actually add functionality to a string, for instance. -String.prototype.firstCharacter = function(){ - return this.charAt(0); +// However, the wrapper objects and the regular builtins share a prototype, so +// you can actually add functionality to a string, for instance. +String.prototype.firstCharacter = function(){ + return this.charAt(0); }; -"abc".firstCharacter(); // = "a" - -// This fact is often used in "polyfilling", which is implementing newer -// features of JavaScript in an older subset of JavaScript, so that they can be -// used in older environments such as outdated browsers. - -// For instance, we mentioned that Object.create isn't yet available in all -// implementations, but we can still use it with this polyfill: -if (Object.create === undefined){ // don't overwrite it if it exists - Object.create = function(proto){ - // make a temporary constructor with the right prototype - var Constructor = function(){}; - Constructor.prototype = proto; - // then use it to create a new, appropriately-prototyped object - return new Constructor(); - }; +"abc".firstCharacter(); // = "a" + +// This fact is often used in "polyfilling", which is implementing newer +// features of JavaScript in an older subset of JavaScript, so that they can be +// used in older environments such as outdated browsers. + +// For instance, we mentioned that Object.create isn't yet available in all +// implementations, but we can still use it with this polyfill: +if (Object.create === undefined){ // don't overwrite it if it exists + Object.create = function(proto){ + // make a temporary constructor with the right prototype + var Constructor = function(){}; + Constructor.prototype = proto; + // then use it to create a new, appropriately-prototyped object + return new Constructor(); + }; } -// ES6 Additions +// ES6 Additions -// The "let" keyword allows you to define variables in a lexical scope,  -// as opposed to a block scope like the var keyword does. -let name = "Billy"; +// The "let" keyword allows you to define variables in a lexical scope,  +// as opposed to a function scope like the var keyword does. +let name = "Billy"; -// Variables defined with let can be reassigned new values. -name = "William"; +// Variables defined with let can be reassigned new values. +name = "William"; -// The "const" keyword allows you to define a variable in a lexical scope -// like with let, but you cannot reassign the value once one has been assigned. +// The "const" keyword allows you to define a variable in a lexical scope +// like with let, but you cannot reassign the value once one has been assigned. -const pi = 3.14; +const pi = 3.14; -pi = 4.13; // You cannot do this. +pi = 4.13; // You cannot do this. -// There is a new syntax for functions in ES6 known as "lambda syntax". -// This allows functions to be defined in a lexical scope like with variables -// defined by const and let.  +// There is a new syntax for functions in ES6 known as "lambda syntax". +// This allows functions to be defined in a lexical scope like with variables +// defined by const and let.  -const isEven = (number) => { - return number % 2 === 0; +const isEven = (number) => { + return number % 2 === 0; }; -isEven(7); // false +isEven(7); // false -// The "equivalent" of this function in the traditional syntax would look like this: +// The "equivalent" of this function in the traditional syntax would look like this: -function isEven(number) { - return number % 2 === 0; +function isEven(number) { + return number % 2 === 0; }; -// I put the word "equivalent" in double quotes because a function defined -// using the lambda syntax cannnot be called before the definition. -// The following is an example of invalid usage: +// I put the word "equivalent" in double quotes because a function defined +// using the lambda syntax cannot be called before the definition. +// The following is an example of invalid usage: -add(1, 8); +add(1, 8); -const add = (firstNumber, secondNumber) => { - return firstNumber + secondNumber; +const add = (firstNumber, secondNumber) => { + return firstNumber + secondNumber; }; diff --git a/tests/results/23 b/tests/results/23 index e869a697..81441f54 100644 --- a/tests/results/23 +++ b/tests/results/23 @@ -22,5 +22,6 @@ print range rosetta/ slices +south meaning switch types diff --git a/tests/results/25 b/tests/results/25 index bd555a8d..e69de29b 100644 --- a/tests/results/25 +++ b/tests/results/25 @@ -1,35 +0,0 @@ -# Latency numbers every programmer should know  - -1ns Main memory reference: Send 2,000 bytes Read 1,000,000 bytes -▗▖ 100ns over commodity network: sequentially from SSD: 61us - ▗▖ 62ns ▗  -L1 cache reference: 1ns ▗  -▗▖ 1us Disk seek: 2ms - ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ SSD random read: 16us ▗▖▗▖▗  -Branch mispredict: 3ns  ▗▖  -▗▖▗▖▗▖  Read 1,000,000 bytes - Compress 1KB with Snappy: Read 1,000,000 bytes sequentially from disk: -L2 cache reference: 4ns 2us sequentially from memory: 947us -▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ 3us ▗  - ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗  -Mutex lock/unlock: 16ns   Packet roundtrip -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  Round trip CA to Netherlands: 150ms -▗▖▗▖▗▖▗▖▗▖▗▖▗ 10us = ▗▖ in same datacenter: 500us ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  - ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -100ns = ▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ 1ms = ▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -  ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  - ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖ ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -# [github.com/chubin/late.nz] [MIT License] ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖   -# Console port of "Jeff Dean's latency numbers" ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  -# from [github.com/colin-scott/interactive_latencies] ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  - ▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖▗▖  diff --git a/tests/results/3 b/tests/results/3 index a271fdb6..eec4b43a 100644 --- a/tests/results/3 +++ b/tests/results/3 @@ -5,7 +5,7 @@ ls # To display everything in , including hidden files: ls -a -# To display all files, along with the size (with unit suffixes) and timestamp +# To display all files, along with the size (with unit suffixes) and timestamp: ls -lh # To display files, sorted by size: @@ -16,6 +16,22 @@ ls -d */ # To display directories only, include hidden: ls -d .*/ */ + +# To display all files sorted by changed date, most recent first: +ls -ltc + +# To display files sorted by create time: +ls -lt + +# To display files in a single column: +ls -1 + +# To show ACLs (MacOS): +# see also `cheat chmod` for `/bin/chmod` options for ACLs +/bin/ls -le + +# To show all the subtree files (Recursive Mode): +ls -R #[tldr:ls] # ls # List directory contents. diff --git a/tests/results/4 b/tests/results/4 index 692a2f66..ff839adf 100644 --- a/tests/results/4 +++ b/tests/results/4 @@ -1,76 +1,76 @@  cheat.sheets:btrfs  -# Create a btrfs file system on /dev/sdb, /dev/sdc, and /dev/sdd -mkfs.btrfs /dev/sdb /dev/sdc /dev/sdd +# Create a btrfs file system on /dev/sdb, /dev/sdc, and /dev/sdd +mkfs.btrfs /dev/sdb /dev/sdc /dev/sdd -# btrfs with just one hard drive, metadata not redundant -# (this is dangerous: if your metadata is lost, your data is lost as well) -mkfs.btrfs -m single /dev/sdb +# btrfs with just one hard drive, metadata not redundant +# (this is dangerous: if your metadata is lost, your data is lost as well) +mkfs.btrfs -m single /dev/sdb -# data to be redundant and metadata to be non-redundant: -mkfs.btrfs -m raid0 -d raid1 /dev/sdb /dev/sdc /dev/sdd +# data to be redundant and metadata to be non-redundant: +mkfs.btrfs -m raid0 -d raid1 /dev/sdb /dev/sdc /dev/sdd -# both data and metadata to be redundant -mkfs.btrfs -d raid1 /dev/sdb /dev/sdc /dev/sdd +# both data and metadata to be redundant +mkfs.btrfs -d raid1 /dev/sdb /dev/sdc /dev/sdd -# To get a list of all btrfs file systems -btrfs filesystem show +# To get a list of all btrfs file systems +btrfs filesystem show -# detailed df for a filesystem (mounted in /mnt) -btrfs filesystem df /mnt +# detailed df for a filesystem (mounted in /mnt) +btrfs filesystem df /mnt -# resize btrfs online (-2g decreases, +2g increases) -btrfs filesystem resize -2g /mnt +# resize btrfs online (-2g decreases, +2g increases) +btrfs filesystem resize -2g /mnt -# use maximum space -btrfs filesystem resize max /mnt +# use maximum space +btrfs filesystem resize max /mnt -# add new device to a filesystem -btrfs device add /dev/sdf /mnt +# add new device to a filesystem +btrfs device add /dev/sdf /mnt -# remove devices from a filesystem -btrfs device delete missing /mnt +# remove devices from a filesystem +btrfs device delete missing /mnt -# create the subvolume /mnt/sv1 in the /mnt volume -btrfs subvolume create /mnt/sv1 +# create the subvolume /mnt/sv1 in the /mnt volume +btrfs subvolume create /mnt/sv1 -# list subvolumes -btrfs subvolume list /mnt +# list subvolumes +btrfs subvolume list /mnt -# mount subvolume without mounting the main filesystem -mount -o subvol=sv1 /dev/sdb /mnt +# mount subvolume without mounting the main filesystem +mount -o subvol=sv1 /dev/sdb /mnt -# delete subvolume -btrfs subvolume delete /mnt/sv1 +# delete subvolume +btrfs subvolume delete /mnt/sv1 -# taking snapshot of a subvolume -btrfs subvolume snapshot /mnt/sv1 /mnt/sv1_snapshot +# taking snapshot of a subvolume +btrfs subvolume snapshot /mnt/sv1 /mnt/sv1_snapshot -# taking snapshot of a file (copy file by reference) -cp --reflink /mnt/sv1/test1 /mnt/sv1/test3 +# taking snapshot of a file (copy file by reference) +cp --reflink /mnt/sv1/test1 /mnt/sv1/test3 -# convert ext3/ext4 to btrfs -btrfs-convert /dev/sdb1 +# convert ext3/ext4 to btrfs +btrfs-convert /dev/sdb1 -# convert btrfs to ext3/ext4 -btrfs-convert -r /dev/sdb1 +# convert btrfs to ext3/ext4 +btrfs-convert -r /dev/sdb1  tldr:btrfs  -# btrfs -# A filesystem based on the copy-on-write (COW) principle for Linux. -# Some subcommands such as `btrfs device` have their own usage documentation. -# More information: . +# btrfs +# A filesystem based on the copy-on-write (COW) principle for Linux. +# Some subcommands such as `btrfs device` have their own usage documentation. +# More information: . -# Create subvolume: -sudo btrfs subvolume create path/to/subvolume +# Create subvolume: +sudo btrfs subvolume create path/to/subvolume -# List subvolumes: -sudo btrfs subvolume list path/to/mount_point +# List subvolumes: +sudo btrfs subvolume list path/to/mount_point -# Show space usage information: -sudo btrfs filesystem df path/to/mount_point +# Show space usage information: +sudo btrfs filesystem df path/to/mount_point -# Enable quota: -sudo btrfs quota enable path/to/subvolume +# Enable quota: +sudo btrfs quota enable path/to/subvolume -# Show quota: -sudo btrfs qgroup show path/to/subvolume +# Show quota: +sudo btrfs qgroup show path/to/subvolume diff --git a/tests/results/5 b/tests/results/5 index d3accee7..d12963c9 100644 --- a/tests/results/5 +++ b/tests/results/5 @@ -1,55 +1,60 @@  cheat.sheets:btrfs  -# create the subvolume /mnt/sv1 in the /mnt volume -btrfs subvolume create /mnt/sv1 +# create the subvolume /mnt/sv1 in the /mnt volume +btrfs subvolume create /mnt/sv1 -# list subvolumes -btrfs subvolume list /mnt +# list subvolumes +btrfs subvolume list /mnt -# mount subvolume without mounting the main filesystem -mount -o subvol=sv1 /dev/sdb /mnt +# mount subvolume without mounting the main filesystem +mount -o subvol=sv1 /dev/sdb /mnt -# delete subvolume -btrfs subvolume delete /mnt/sv1 +# delete subvolume +btrfs subvolume delete /mnt/sv1 -# taking snapshot of a subvolume -btrfs subvolume snapshot /mnt/sv1 /mnt/sv1_snapshot +# taking snapshot of a subvolume +btrfs subvolume snapshot /mnt/sv1 /mnt/sv1_snapshot  tldr:btrfs  -# Create subvolume: -sudo btrfs subvolume create path/to/subvolume +# Create subvolume: +sudo btrfs subvolume create path/to/subvolume -# List subvolumes: -sudo btrfs subvolume list path/to/mount_point +# List subvolumes: +sudo btrfs subvolume list path/to/mount_point -# Enable quota: -sudo btrfs quota enable path/to/subvolume +# Enable quota: +sudo btrfs quota enable path/to/subvolume -# Show quota: -sudo btrfs qgroup show path/to/subvolume +# Show quota: +sudo btrfs qgroup show path/to/subvolume  tldr:btrfs-filesystem  -# Defragment a directory recursively (does not cross subvolume boundaries): -sudo btrfs filesystem defragment -v -r path/to/directory +# Defragment a directory recursively (does not cross subvolume boundaries): +sudo btrfs filesystem defragment -v -r path/to/directory + + tldr:btrfs-property  +# btrfs property +# Get, set, or list properties for a given btrfs filesystem object (files, directories, subvolumes, filesystems, or devices). +# More information: .  tldr:btrfs-subvolume  -# btrfs subvolume -# Manage btrfs subvolumes and snapshots. -# More information: . +# btrfs subvolume +# Manage btrfs subvolumes and snapshots. +# More information: . -# Create a new empty subvolume: -sudo btrfs subvolume create path/to/new_subvolume +# Create a new empty subvolume: +sudo btrfs subvolume create path/to/new_subvolume -# List all subvolumes and snapshots in the specified filesystem: -sudo btrfs subvolume list path/to/btrfs_filesystem +# List all subvolumes and snapshots in the specified filesystem: +sudo btrfs subvolume list path/to/btrfs_filesystem -# Delete a subvolume: -sudo btrfs subvolume delete path/to/subvolume +# Delete a subvolume: +sudo btrfs subvolume delete path/to/subvolume -# Create a read-only snapshot of an existing subvolume: -sudo btrfs subvolume snapshot -r path/to/source_subvolume path/to/target +# Create a read-only snapshot of an existing subvolume: +sudo btrfs subvolume snapshot -r path/to/source_subvolume path/to/target -# Create a read-write snapshot of an existing subvolume: -sudo btrfs subvolume snapshot path/to/source_subvolume path/to/target +# Create a read-write snapshot of an existing subvolume: +sudo btrfs subvolume snapshot path/to/source_subvolume path/to/target -# Show detailed information about a subvolume: -sudo btrfs subvolume show path/to/subvolume +# Show detailed information about a subvolume: +sudo btrfs subvolume show path/to/subvolume diff --git a/tests/results/9 b/tests/results/9 index a8eca4f0..54d42a50 100644 --- a/tests/results/9 +++ b/tests/results/9 @@ -1,16 +1,23 @@ -# How do I copy a file in Python? +# [`shutil`][1] has many methods you can use. One of which is: #  -# shutil (http://docs.python.org/3/library/shutil.html) has many methods -# you can use. One of which is: - -from shutil import copyfile - -copyfile(src, dst) - -# Copy the contents of the file named src to a file named dst. The -# destination location must be writable; otherwise, an IOError exception -# will be raised. If dst already exists, it will be replaced. Special -# files such as character or block devices and pipes cannot be copied -# with this function. src and dst are path names given as strings. +# ``` +# from shutil import copyfile +# copyfile(src, dst) +# ``` +#  + # - Copy the contents of the file named **src** to a file named +# **dst**. + # - The destination location must be writable; otherwise, an +# **IOError** exception will be raised. + # - If **dst** already exists, it will be replaced. + # - Special files such as character or block devices and pipes cannot +# be copied with this function. + # - With **copy**, **src** and **dst** are path names given as +# __strings__. +#  +# If you use `os.path` operations, use `copy` rather than `copyfile`. +# `copyfile` will only accept strings. +#  + # [1]: http://docs.python.org/3/library/shutil.html #  # [Swati] [so/q/123198] [cc by-sa 3.0] From 7dd29302924a15bb6deb141efd692c5f0586ec08 Mon Sep 17 00:00:00 2001 From: Bayram Tagiev Date: Thu, 8 Jun 2023 12:06:30 +0300 Subject: [PATCH 2/2] tests: Added new trailing slash tests --- tests/results/26 | 310 +++++++++++++++++++++++++++++++++++++++++++++++ tests/results/27 | 310 +++++++++++++++++++++++++++++++++++++++++++++++ tests/tests.txt | 2 + 3 files changed, 622 insertions(+) create mode 100644 tests/results/26 create mode 100644 tests/results/27 diff --git a/tests/results/26 b/tests/results/26 new file mode 100644 index 00000000..d14ec1f9 --- /dev/null +++ b/tests/results/26 @@ -0,0 +1,310 @@ +// This is a comment. Line comments look like this... +// and extend multiple lines like this. + +/// Documentation comments look like this and support markdown notation. +/// # Examples +/// +/// ``` +/// let five = 5 +/// ``` + +/////////////// +// 1. Basics // +/////////////// + +#[allow(dead_code)] +// Functions +// `i32` is the type for 32-bit signed integers +fn add2(x: i32, y: i32) -> i32 { + // Implicit return (no semicolon) + x + y +} + +#[allow(unused_variables)] +#[allow(unused_assignments)] +#[allow(dead_code)] +// Main function +fn main() { + // Numbers // + + // Immutable bindings + let x: i32 = 1; + + // Integer/float suffixes + let y: i32 = 13i32; + let f: f64 = 1.3f64; + + // Type inference + // Most of the time, the Rust compiler can infer what type a variable is, so + // you don’t have to write an explicit type annotation. + // Throughout this tutorial, types are explicitly annotated in many places, + // but only for demonstrative purposes. Type inference can handle this for + // you most of the time. + let implicit_x = 1; + let implicit_f = 1.3; + + // Arithmetic + let sum = x + y + 13; + + // Mutable variable + let mut mutable = 1; + mutable = 4; + mutable += 2; + + // Strings // + + // String literals + let x: &str = "hello world!"; + + // Printing + println!("{} {}", f, x); // 1.3 hello world + + // A `String` – a heap-allocated string + // Stored as a `Vec` and always hold a valid UTF-8 sequence,  + // which is not null terminated. + let s: String = "hello world".to_string(); + + // A string slice – an immutable view into another string + // This is basically an immutable pair of pointers to a string – it doesn’t + // actually contain the contents of a string, just a pointer to + // the begin and a pointer to the end of a string buffer, + // statically allocated or contained in another object (in this case, `s`). + // The string slice is like a view `&[u8]` into `Vec`. + let s_slice: &str = &s; + + println!("{} {}", s, s_slice); // hello world hello world + + // Vectors/arrays // + + // A fixed-size array + let four_ints: [i32; 4] = [1, 2, 3, 4]; + + // A dynamic array (vector) + let mut vector: Vec<i32> = vec![1, 2, 3, 4]; + vector.push(5); + + // A slice – an immutable view into a vector or array + // This is much like a string slice, but for vectors + let slice: &[i32] = &vector; + + // Use `{:?}` to print something debug-style + println!("{:?} {:?}", vector, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] + + // Tuples // + + // A tuple is a fixed-size set of values of possibly different types + let x: (i32, &str, f64) = (1, "hello", 3.4); + + // Destructuring `let` + let (a, b, c) = x; + println!("{} {} {}", a, b, c); // 1 hello 3.4 + + // Indexing + println!("{}", x.1); // hello + + ////////////// + // 2. Types // + ////////////// + + // Struct + struct Point { + x: i32, + y: i32, + } + + let origin: Point = Point { x: 0, y: 0 }; + + // A struct with unnamed fields, called a ‘tuple struct’ + struct Point2(i32, i32); + + let origin2 = Point2(0, 0); + + // Basic C-like enum + enum Direction { + Left, + Right, + Up, + Down, + } + + let up = Direction::Up; + + // Enum with fields + enum OptionalI32 { + AnI32(i32), + Nothing, + } + + let two: OptionalI32 = OptionalI32::AnI32(2); + let nothing = OptionalI32::Nothing; + + // Generics // + + struct Foo<T> { bar: T } + + // This is defined in the standard library as `Option` + enum Optional<T> { + SomeVal(T), + NoVal, + } + + // Methods // + + impl<T> Foo<T> { + // Methods take an explicit `self` parameter + fn bar(&self) -> &T { // self is borrowed + &self.bar + } + fn bar_mut(&mut self) -> &mut T { // self is mutably borrowed + &mut self.bar + } + fn into_bar(self) -> T { // here self is consumed + self.bar + } + } + + let a_foo = Foo { bar: 1 }; + println!("{}", a_foo.bar()); // 1 + + // Traits (known as interfaces or typeclasses in other languages) // + + trait Frobnicate<T> { + fn frobnicate(self) -> Option<T>; + } + + impl<T> Frobnicate<T> for Foo<T> { + fn frobnicate(self) -> Option<T> { + Some(self.bar) + } + } + + let another_foo = Foo { bar: 1 }; + println!("{:?}", another_foo.frobnicate()); // Some(1) + + // Function pointer types //  + + fn fibonacci(n: u32) -> u32 { + match n { + 0 => 1, + 1 => 1, + _ => fibonacci(n - 1) + fibonacci(n - 2), + } + } + + type FunctionPointer = fn(u32) -> u32; + + let fib : FunctionPointer = fibonacci; + println!("Fib: {}", fib(4)); // 5 + + ///////////////////////// + // 3. Pattern matching // + ///////////////////////// + + let foo = OptionalI32::AnI32(1); + match foo { + OptionalI32::AnI32(n) => println!("it’s an i32: {}", n), + OptionalI32::Nothing => println!("it’s nothing!"), + } + + // Advanced pattern matching + struct FooBar { x: i32, y: OptionalI32 } + let bar = FooBar { x: 15, y: OptionalI32::AnI32(32) }; + + match bar { + FooBar { x: 0, y: OptionalI32::AnI32(0) } => + println!("The numbers are zero!"), + FooBar { x: n, y: OptionalI32::AnI32(m) } if n == m => + println!("The numbers are the same"), + FooBar { x: n, y: OptionalI32::AnI32(m) } => + println!("Different numbers: {} {}", n, m), + FooBar { x: _, y: OptionalI32::Nothing } => + println!("The second number is Nothing!"), + } + + ///////////////////// + // 4. Control flow // + ///////////////////// + + // `for` loops/iteration + let array = [1, 2, 3]; + for i in array { + println!("{}", i); + } + + // Ranges + for i in 0u32..10 { + print!("{} ", i); + } + println!(""); + // prints `0 1 2 3 4 5 6 7 8 9 ` + + // `if` + if 1 == 1 { + println!("Maths is working!"); + } else { + println!("Oh no..."); + } + + // `if` as expression + let value = if true { + "good" + } else { + "bad" + }; + + // `while` loop + while 1 == 1 { + println!("The universe is operating normally."); + // break statement gets out of the while loop. + // It avoids useless iterations. + break + } + + // Infinite loop + loop { + println!("Hello!"); + // break statement gets out of the loop + break + } + + ///////////////////////////////// + // 5. Memory safety & pointers // + ///////////////////////////////// + + // Owned pointer – only one thing can ‘own’ this pointer at a time + // This means that when the `Box` leaves its scope, it can be automatically deallocated safely. + let mut mine: Box<i32> = Box::new(3); + *mine = 5; // dereference + // Here, `now_its_mine` takes ownership of `mine`. In other words, `mine` is moved. + let mut now_its_mine = mine; + *now_its_mine += 2; + + println!("{}", now_its_mine); // 7 + // println!("{}", mine); // this would not compile because `now_its_mine` now owns the pointer + + // Reference – an immutable pointer that refers to other data + // When a reference is taken to a value, we say that the value has been ‘borrowed’. + // While a value is borrowed immutably, it cannot be mutated or moved. + // A borrow is active until the last use of the borrowing variable. + let mut var = 4; + var = 3; + let ref_var: &i32 = &var; + + println!("{}", var); // Unlike `mine`, `var` can still be used + println!("{}", *ref_var); + // var = 5; // this would not compile because `var` is borrowed + // *ref_var = 6; // this would not either, because `ref_var` is an immutable reference + ref_var; // no-op, but counts as a use and keeps the borrow active + var = 2; // ref_var is no longer used after the line above, so the borrow has ended + + // Mutable reference + // While a value is mutably borrowed, it cannot be accessed at all. + let mut var2 = 4; + let ref_var2: &mut i32 = &mut var2; + *ref_var2 += 2; // '*' is used to point to the mutably borrowed var2 + + println!("{}", *ref_var2); // 6 , // var2 would not compile. + // ref_var2 is of type &mut i32, so stores a reference to an i32, not the value. + // var2 = 2; // this would not compile because `var2` is borrowed. + ref_var2; // no-op, but counts as a use and keeps the borrow active until here +} diff --git a/tests/results/27 b/tests/results/27 new file mode 100644 index 00000000..d14ec1f9 --- /dev/null +++ b/tests/results/27 @@ -0,0 +1,310 @@ +// This is a comment. Line comments look like this... +// and extend multiple lines like this. + +/// Documentation comments look like this and support markdown notation. +/// # Examples +/// +/// ``` +/// let five = 5 +/// ``` + +/////////////// +// 1. Basics // +/////////////// + +#[allow(dead_code)] +// Functions +// `i32` is the type for 32-bit signed integers +fn add2(x: i32, y: i32) -> i32 { + // Implicit return (no semicolon) + x + y +} + +#[allow(unused_variables)] +#[allow(unused_assignments)] +#[allow(dead_code)] +// Main function +fn main() { + // Numbers // + + // Immutable bindings + let x: i32 = 1; + + // Integer/float suffixes + let y: i32 = 13i32; + let f: f64 = 1.3f64; + + // Type inference + // Most of the time, the Rust compiler can infer what type a variable is, so + // you don’t have to write an explicit type annotation. + // Throughout this tutorial, types are explicitly annotated in many places, + // but only for demonstrative purposes. Type inference can handle this for + // you most of the time. + let implicit_x = 1; + let implicit_f = 1.3; + + // Arithmetic + let sum = x + y + 13; + + // Mutable variable + let mut mutable = 1; + mutable = 4; + mutable += 2; + + // Strings // + + // String literals + let x: &str = "hello world!"; + + // Printing + println!("{} {}", f, x); // 1.3 hello world + + // A `String` – a heap-allocated string + // Stored as a `Vec` and always hold a valid UTF-8 sequence,  + // which is not null terminated. + let s: String = "hello world".to_string(); + + // A string slice – an immutable view into another string + // This is basically an immutable pair of pointers to a string – it doesn’t + // actually contain the contents of a string, just a pointer to + // the begin and a pointer to the end of a string buffer, + // statically allocated or contained in another object (in this case, `s`). + // The string slice is like a view `&[u8]` into `Vec`. + let s_slice: &str = &s; + + println!("{} {}", s, s_slice); // hello world hello world + + // Vectors/arrays // + + // A fixed-size array + let four_ints: [i32; 4] = [1, 2, 3, 4]; + + // A dynamic array (vector) + let mut vector: Vec<i32> = vec![1, 2, 3, 4]; + vector.push(5); + + // A slice – an immutable view into a vector or array + // This is much like a string slice, but for vectors + let slice: &[i32] = &vector; + + // Use `{:?}` to print something debug-style + println!("{:?} {:?}", vector, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] + + // Tuples // + + // A tuple is a fixed-size set of values of possibly different types + let x: (i32, &str, f64) = (1, "hello", 3.4); + + // Destructuring `let` + let (a, b, c) = x; + println!("{} {} {}", a, b, c); // 1 hello 3.4 + + // Indexing + println!("{}", x.1); // hello + + ////////////// + // 2. Types // + ////////////// + + // Struct + struct Point { + x: i32, + y: i32, + } + + let origin: Point = Point { x: 0, y: 0 }; + + // A struct with unnamed fields, called a ‘tuple struct’ + struct Point2(i32, i32); + + let origin2 = Point2(0, 0); + + // Basic C-like enum + enum Direction { + Left, + Right, + Up, + Down, + } + + let up = Direction::Up; + + // Enum with fields + enum OptionalI32 { + AnI32(i32), + Nothing, + } + + let two: OptionalI32 = OptionalI32::AnI32(2); + let nothing = OptionalI32::Nothing; + + // Generics // + + struct Foo<T> { bar: T } + + // This is defined in the standard library as `Option` + enum Optional<T> { + SomeVal(T), + NoVal, + } + + // Methods // + + impl<T> Foo<T> { + // Methods take an explicit `self` parameter + fn bar(&self) -> &T { // self is borrowed + &self.bar + } + fn bar_mut(&mut self) -> &mut T { // self is mutably borrowed + &mut self.bar + } + fn into_bar(self) -> T { // here self is consumed + self.bar + } + } + + let a_foo = Foo { bar: 1 }; + println!("{}", a_foo.bar()); // 1 + + // Traits (known as interfaces or typeclasses in other languages) // + + trait Frobnicate<T> { + fn frobnicate(self) -> Option<T>; + } + + impl<T> Frobnicate<T> for Foo<T> { + fn frobnicate(self) -> Option<T> { + Some(self.bar) + } + } + + let another_foo = Foo { bar: 1 }; + println!("{:?}", another_foo.frobnicate()); // Some(1) + + // Function pointer types //  + + fn fibonacci(n: u32) -> u32 { + match n { + 0 => 1, + 1 => 1, + _ => fibonacci(n - 1) + fibonacci(n - 2), + } + } + + type FunctionPointer = fn(u32) -> u32; + + let fib : FunctionPointer = fibonacci; + println!("Fib: {}", fib(4)); // 5 + + ///////////////////////// + // 3. Pattern matching // + ///////////////////////// + + let foo = OptionalI32::AnI32(1); + match foo { + OptionalI32::AnI32(n) => println!("it’s an i32: {}", n), + OptionalI32::Nothing => println!("it’s nothing!"), + } + + // Advanced pattern matching + struct FooBar { x: i32, y: OptionalI32 } + let bar = FooBar { x: 15, y: OptionalI32::AnI32(32) }; + + match bar { + FooBar { x: 0, y: OptionalI32::AnI32(0) } => + println!("The numbers are zero!"), + FooBar { x: n, y: OptionalI32::AnI32(m) } if n == m => + println!("The numbers are the same"), + FooBar { x: n, y: OptionalI32::AnI32(m) } => + println!("Different numbers: {} {}", n, m), + FooBar { x: _, y: OptionalI32::Nothing } => + println!("The second number is Nothing!"), + } + + ///////////////////// + // 4. Control flow // + ///////////////////// + + // `for` loops/iteration + let array = [1, 2, 3]; + for i in array { + println!("{}", i); + } + + // Ranges + for i in 0u32..10 { + print!("{} ", i); + } + println!(""); + // prints `0 1 2 3 4 5 6 7 8 9 ` + + // `if` + if 1 == 1 { + println!("Maths is working!"); + } else { + println!("Oh no..."); + } + + // `if` as expression + let value = if true { + "good" + } else { + "bad" + }; + + // `while` loop + while 1 == 1 { + println!("The universe is operating normally."); + // break statement gets out of the while loop. + // It avoids useless iterations. + break + } + + // Infinite loop + loop { + println!("Hello!"); + // break statement gets out of the loop + break + } + + ///////////////////////////////// + // 5. Memory safety & pointers // + ///////////////////////////////// + + // Owned pointer – only one thing can ‘own’ this pointer at a time + // This means that when the `Box` leaves its scope, it can be automatically deallocated safely. + let mut mine: Box<i32> = Box::new(3); + *mine = 5; // dereference + // Here, `now_its_mine` takes ownership of `mine`. In other words, `mine` is moved. + let mut now_its_mine = mine; + *now_its_mine += 2; + + println!("{}", now_its_mine); // 7 + // println!("{}", mine); // this would not compile because `now_its_mine` now owns the pointer + + // Reference – an immutable pointer that refers to other data + // When a reference is taken to a value, we say that the value has been ‘borrowed’. + // While a value is borrowed immutably, it cannot be mutated or moved. + // A borrow is active until the last use of the borrowing variable. + let mut var = 4; + var = 3; + let ref_var: &i32 = &var; + + println!("{}", var); // Unlike `mine`, `var` can still be used + println!("{}", *ref_var); + // var = 5; // this would not compile because `var` is borrowed + // *ref_var = 6; // this would not either, because `ref_var` is an immutable reference + ref_var; // no-op, but counts as a use and keeps the borrow active + var = 2; // ref_var is no longer used after the line above, so the borrow has ended + + // Mutable reference + // While a value is mutably borrowed, it cannot be accessed at all. + let mut var2 = 4; + let ref_var2: &mut i32 = &mut var2; + *ref_var2 += 2; // '*' is used to point to the mutably borrowed var2 + + println!("{}", *ref_var2); // 6 , // var2 would not compile. + // ref_var2 is of type &mut i32, so stores a reference to an i32, not the value. + // var2 = 2; // this would not compile because `var2` is borrowed. + ref_var2; // no-op, but counts as a use and keeps the borrow active until here +} diff --git a/tests/tests.txt b/tests/tests.txt index 86bcc529..b7a2dd89 100644 --- a/tests/tests.txt +++ b/tests/tests.txt @@ -23,3 +23,5 @@ javascript/:learn # short names check emacs:go-mode/:list # special editor names mkffs.ffatt # unknown latencies # [python2] +rust/:learn +rust/:learn/