text:
using Markdown
using InteractiveUtils

# ╔═╡ 32be2dac-7618-11eb-2ea5-9f165c3c91e1
begin
    import Pkg
	io = IOBuffer()
    Pkg.activate(io = io)
	deps = [pair.second for pair in Pkg.dependencies()]
	direct_deps = filter(p -> p.is_direct_dep, deps)
    pkgs = [x.name for x in direct_deps]
	if "NativeSVG" ∉ pkgs
		Pkg.add(url="https://github.com/BenLauwens/NativeSVG.jl.git")
	end
	using NativeSVG
end

# ╔═╡ 334f2774-7610-11eb-197e-eb4c20530a0c
md"""# Fruitful Functions

Many of the Julia functions we have used, such as the math functions, produce return values. But the functions we've written are all void: they have an effect, like printing a value or moving a turtle, but they return nothing. In this chapter you will learn to write fruitful functions."""

# ╔═╡ b1a8c332-7610-11eb-1b18-f7bf7f28ea27
md"""## Return Values

Calling a function generates a return value, which we usually assign to a variable or use as part of an expression:

```julia
e = exp(1.0)
height = radius * sin(radians)
```

!!! tip
    Julia provides the Euler's number ``\mathcal e`` by the symbol `ℯ` (**`\euler TAB`**).

The functions we have written so far are void. Speaking casually, they have no return value; more precisely, their return value is nothing. In this chapter, we are (finally) going to write fruitful functions. The first example is area, which returns the area of a circle with the given radius:
"""

# ╔═╡ fbb22aac-ed8a-4e25-8fb7-515798a7f72d
function area(radius)
	a = π * radius^2
	return a
end

# ╔═╡ b96ba715-ddda-47af-9dac-407923b6d03a
md"""We have seen the return statement before, but in a fruitful function the return statement includes an expression. This statement means: "Return immediately from this function and use the following expression as a return value." The expression can be arbitrarily complicated, so we could have written this function more concisely:

```julia
function area(radius)
	π * radius^2
end
```

where the last expression is automatically returned; or

```julia
area(radius) = π * radius^2
```

but this is only usefull for a function consisting of a oneline expression.

However, *temporary variables* like `a` and explicit return statements can make debugging easier.

The value returned by a function is the value of the last expression evaluated, which, by default, is the last expression in the body of the function definition.

Sometimes it is useful to have multiple return statements, one in each branch of a conditional:
"""

# ╔═╡ 6887201f-1ebb-4201-8cd4-6f592aa12efd
function absvalue(x)
	if x < 0
		return -x
	else
		return x
	end
end

# ╔═╡ c9767a6b-ce21-4843-9bcb-330af6444fd8
md"""or

```julia
function absvalue(x)
	if x < 0
		-x
	else
		x
	end
end
```

because the last expression evaluated is automatically returned.

Since these return statements are in an alternative conditional, only one runs.

As soon as a return statement runs, the function terminates without executing any subsequent statements. Code that appears after a return statement, or any other place the flow of execution can never reach, is called *dead code*.

In a fruitful function, it is a good idea to ensure that every possible path through the program hits a return statement. Consider this example:
"""

# ╔═╡ 129075a2-a215-4905-8d6e-d04da70fe69a
function absvalue_err(x)
	if x < 0
		return -x
	end
	if x > 0
		return x
	end
end

# ╔═╡ 4e7abb20-5521-436e-a9fa-9bfd0fbdf47e
md"""This function is incorrect because if `x` happens to be `0`, neither condition is true, and the function ends without hitting a return statement. If the flow of execution gets to the end of a function, the return value is `nothing`, which is not the absolute value of `0`.
"""

# ╔═╡ 131480f6-71d7-42a3-a7b0-a2112ef2abfe
show(absvalue_err(0))

# ╔═╡ 1a73c7ad-bc08-415a-b37f-ebe7acc8a8a9
md"""!!! tip
    Julia provides a built-in function called `abs` that computes absolute values.
"""

# ╔═╡ 4219f3ac-7612-11eb-3167-f55e643f9235
md"""#### Exercise 6-1

Write a compare function that takes two values, `x` and `y`, and returns `1` if `x > y`, `0` if `x == y`, and `-1` if `x < y`.
"""

# ╔═╡ 8b79bba4-7682-11eb-2ea1-0986a9911b40
md"""!!! languages
    In Python and the C programming language, `return` cannot be omitted, neither is the last evaluated expression returned automatically.

    ```python
    def absvalue(x):
        if x < 0:
            return -x
        else:
            return x

    ```

    The return type has to be provided in C:

    ```c
    double absvalue(double x) {
        if (x < 0) {
            return -x;
        } else {
            return x;
        }
    }
    ```

    MATLAB uses a `return` statement without argument. A function stops after this statements and returns the values specified in the header:

    ```matlab
    function [ret] = absvalue(x)
        if x < 0
            ret = -x;
        else
            ret = x;
        end
    end
    ```
"""

# ╔═╡ bfecb80e-7612-11eb-0633-035cbcd3e426
md"""## Incremental Development

As you write larger functions, you might find yourself spending more time debugging.

To deal with increasingly complex programs, you might want to try a process called *incremental development*. The goal of incremental development is to avoid long debugging sessions by adding and testing only a small amount of code at a time.

As an example, suppose you want to find the distance between two points, given by the coordinates ``(x_1, y_1)`` and ``(x_2, y_2)``. By the Pythagorean theorem, the distance is:

```math
d=\sqrt{(x_2−x_1)^2+(y_2−y_1)^2}
```

The first step is to consider what a distance function should look like in Julia. In other words, what are the inputs (parameters) and what is the output (return value)?

In this case, the inputs are two points, which you can represent using four numbers. The return value is the distance represented by a floating-point value.

Immediately you can write an outline of the function and call it with sample arguments:
"""

# ╔═╡ e4dc510b-c45a-45ad-8f36-c173c3fd587e
let
	function distance(x₁, y₁, x₂, y₂)
		return 0.0
	end

	distance(1.0, 2.0, 4.0, 6.0)
end

# ╔═╡ bb192f6d-32bc-4a78-8360-eba58e73b5ca
md"""Obviously, this version doesn't compute distances; it always returns zero. But it is syntactically correct, and it runs, which means that you can test it before you make it more complicated. The subscript numbers are available in the Unicode character encoding (**`\_1 TAB`**, **`\_2 TAB`**, etc.).

I chose the sample arguments so that the horizontal distance is ``3`` and the vertical distance is ``4``; that way, the result is ``5``, the hypotenuse of a 3-4-5 triangle. When testing a function, it is useful to know the right answer.

At this point we have confirmed that the function is syntactically correct, and we can start adding code to the body. A reasonable next step is to find the differences ``x_2 − x_1`` and ``y_2 − y_1``. The next version stores those values in temporary variables and prints them with the `@show` macro:
"""

# ╔═╡ 54c72011-910e-45e9-a597-ccdc4dff6743
let
	function distance(x₁, y₁, x₂, y₂)
		dx = x₂ - x₁
		dy = y₂ - y₁
		@show dx dy
		return 0.0
	end

	distance(1.0, 2.0, 4.0, 6.0)
end

# ╔═╡ e787ee70-f4d0-4e0b-a9ab-88411565eb85
md"""If the function is working, it should display `dx = 3` and `dy = 4`. If so, we know that the function is getting the right arguments and performing the first computation correctly. If not, there are only a few lines to check.

Next, we compute the sum of squares of `dx` and `dy`:
"""

# ╔═╡ 58a165a4-942b-4cf0-aabe-bc68aee3c34c
let
	function distance(x₁, y₁, x₂, y₂)
		dx = x₂ - x₁
		dy = y₂ - y₁
		d² = dx^2 + dy^2
		@show d²
		return 0.0
	end

	distance(1.0, 2.0, 4.0, 6.0)
end

# ╔═╡ 4374af23-b021-4ac9-8bb1-5fe7fd896cf3
md"""Again, you would run the program at this stage and check the output (which should be `25`). Superscript numbers are also available (**`\^2 TAB`**). Finally, you can use `sqrt` or `√`(**`\sqrt TAB`**) to compute and return the result:
"""

# ╔═╡ 4c5f679a-0a37-4279-be37-2c53fe0d925c
function distance(x₁, y₁, x₂, y₂)
	dx = x₂ - x₁
	dy = y₂ - y₁
	d² = dx^2 + dy^2
	return √d²
end

# ╔═╡ bb9f9b67-d76a-4956-9fbe-6b0a934eeb0e
distance(1.0, 2.0, 4.0, 6.0)

# ╔═╡ f9f26b03-0cde-4428-aac5-236fb7164b34
md"""If that works correctly, you are done. Otherwise, you might want to print the value of `√d²` before the return statement.

The final version of the function doesn't display anything when it runs; it only returns a value. The print statements we wrote are useful for debugging, but once you get the function working, you should remove them. Code like that is called *scaffolding* because it is helpful for building the program but is not part of the final product.

When you start out, you should add only a line or two of code at a time. As you gain more experience, you might find yourself writing and debugging bigger chunks. Either way, incremental development can save you a lot of debugging time.

The key aspects of the process are:

1. Start with a working program and make small, incremental changes. At any point, if there is an error, you should have a good idea where it is.
2. Use variables to hold intermediate values so you can display and check them.
3. Once the program is working, you might want to remove some of the scaffolding or consolidate multiple statements into compound expressions, but only if it does not make the program difficult to read.
"""

# ╔═╡ 8d9ff285-6907-4071-b208-7d8fc702a59b
md"""We used `let` blocks to create new local definitions of the `distance` function to illustrate the different steps. Normally, you modify the code in the cell during the development process. As a best practice, you create the function call with default parameters before the function definition. In the notebook interface it will be automatically executed every time you modify the function definition."""

# ╔═╡ f5edc4c2-7613-11eb-0765-cba4f0286212
md"""#### Exercise 6-2

Use incremental development to write a function called hypotenuse that returns the length of the hypotenuse of a right triangle given the lengths of the other two legs as arguments. Record each stage of the development process as you go."""

# ╔═╡ 47e45c90-7615-11eb-0fe7-358b9d219497
md""" ## Composition

As you should expect by now, you can call one function from within another. As an example, we'll write a function that takes two points, the center of the circle and a point on the perimeter, and computes the area of the circle.

Assume that the center point is stored in the variables `xc` and `yc`, and the perimeter point is in `xp` and `yp`. The first step is to find the radius of the circle, which is the distance between the two points. We just wrote a function, distance, that does that:

```julia
radius = distance(xc, yc, xp, yp)
```

The next step is to find the area of a circle with that radius; we just wrote that, too:

```julia
result = area(radius)
```

Encapsulating these steps in a function, we get:

```julia
function circlearea(xc, yc, xp, yp)
	radius = distance(xc, yc, xp, yp)
	result = area(radius)
	return result
end
```

The temporary variables `radius` and `result` are useful for development and debugging, but once the program is working, we can make it more concise by composing the function calls:
"""

# ╔═╡ 80890607-b4be-4541-bea0-11744cabbadb
begin
	circlearea(xc, yc, xp, yp) = area(distance(xc, yc, xp, yp))
	circlearea(1.0, 2.0, 4.0, 6.0)
end

# ╔═╡ a74ddcba-7615-11eb-1ba0-c1d9a4eacfb5
md"""## Boolean Functions

Functions can return Booleans, which is often convenient for hiding complicated tests inside functions. For example:
"""

# ╔═╡ aa7f4b2d-a6c9-4c61-ae18-9c929ecd117e
function isdivisible(x, y)
	if x % y == 0
		return true
	else
		return false
	end
end

# ╔═╡ 67568605-8fc5-4f8a-8f87-387d7663cb70
md"""It is common to give Boolean functions names that sound like yes/no questions; `isdivisible` returns either `true` or `false` to indicate whether `x` is divisible by `y`.

Here is an example:
"""

# ╔═╡ 5fa7bb83-b035-4ddf-9447-7eecfa09e952
isdivisible(6, 4)

# ╔═╡ 69a47f53-bc26-4603-a1fd-47f0ccecfffe
isdivisible(6, 3)

# ╔═╡ cf96bc1e-a42f-42fd-a3b1-e6318da2daf0
md"""The result of the `==` operator is a Boolean, so we can write the function more concisely by returning it directly:

```julia
isdivisible(x, y) =  x % y == 0
```

Boolean functions are often used in conditional statements:
"""

# ╔═╡ b292289e-4cda-4725-be1f-0b7dfc49e31d
if isdivisible(6, 3)
	println("6 is divisible by 3")
end

# ╔═╡ ef5158e3-65b4-4979-9843-1f7c8ef757bb
md"""It might be tempting to write something like:

```julia
if isdivisible(x, y) == true
	println("x is divisible by y")
end
```

But the extra comparison with `true` is unnecessary.
"""

# ╔═╡ 3a20604e-7616-11eb-20c6-1fb57dbbb3c8
md"""#### Exercise 6-3
Write a function `isbetween(x, y, z)` that returns `true` if `x ≤ y ≤ z` or `false` otherwise.
"""

# ╔═╡ 53822bd0-7616-11eb-08df-0b6ef72120a8
md"""## More Recursion

We have only covered a small subset of Julia, but you might be interested to know that this subset is a *complete* programming language, which means that anything that can be computed can be expressed in this language. Any program ever written could be rewritten using only the language features you have learned so far (actually, you would need a few commands to control devices like the mouse, disks, etc., but that's all).

Proving that claim is a nontrivial exercise first accomplished by Alan Turing, one of the first computer scientists (some would argue that he was a mathematician, but a lot of early computer scientists started as mathematicians). Accordingly, it is known as the Turing thesis. For a more complete (and accurate) discussion of the Turing thesis, I recommend Michael Sipser's book *Introduction to the Theory of Computation* (Cengage).

To give you an idea of what you can do with the tools you have learned so far, we'll evaluate a few recursively defined mathematical functions. A recursive definition is similar to a circular definition, in the sense that the definition contains a reference to the thing being defined. A truly circular definition is not very useful:

*vorpal*:
An adjective used to describe something that is vorpal.

If you saw that definition in the dictionary, you might be annoyed. On the other hand, if you looked up the definition of the factorial function, denoted with the symbol ``!``, you might get something like this:

```math
n!=\begin{cases}
1 & \textrm{if }n=0\\
n(n-1)! & \textrm{if }n>0
\end{cases}
```

This definition says that the factorial of ``0`` is ``1``, and the factorial of any other value, ``n``, is ``n`` multiplied by the factorial of ``n − 1``.

So, ``3!`` is ``3`` times ``2!``, which is ``2`` times ``1!``, which is ``1`` times ``0!``. Putting it all together, ``3!`` equals ``3`` times ``2`` times ``1`` times ``1``, which is ``6``.

If you can write a recursive definition of something, you can write a Julia program to evaluate it. The first step is to decide what the parameters should be. In this case it should be clear that factorial takes an integer:
"""

# ╔═╡ fe51d5b9-30ae-4b09-b4d0-6bd312e18df2
let
	function fact(n)
		return 0
	end
	@show fact(0)
	@show fact(5)
end;

# ╔═╡ aba2610e-6673-42cd-9db8-1bb14adc3c6a
md"""We have created an outline of the function `fact` and two calls with default parameters. The `@show` macro displays the function evaluations. The semi-colon after the `end` keyword of the `let` block suppresses the output.

If the argument happens to be `0` all we have to do is return `1`:
"""

# ╔═╡ 0091c836-cb15-4ecf-b001-0bafb5143c31
let
	function fact(n)
		if n == 0
			return 1
		end
		return 0
	end
	@show fact(0)
	@show fact(5)
end;

# ╔═╡ dc3e37f9-d686-4e72-9b46-5fcbba041f5b
md"""Otherwise, and this is the interesting part, we have to make a recursive call to find the factorial of `n-1` and then multiply it by `n`:
"""

# ╔═╡ c665c76f-1b7f-4b61-976f-c134a670fccf
begin
	function fact(n)
		if n == 0
			return 1
		end
		recurse = fact(n-1)
		result = n * recurse
		return result
	end
	@show fact(0)
	@show fact(5)
end;

# ╔═╡ dc241e23-e6d5-4997-b7fa-1e44d66226c0
md"""The flow of execution for this program is similar to the flow of `countdown` in "Recursion". If we call fact with the value `3`:

* Since `3` is not `0`, we take the second branch and calculate the factorial of `n-1`...
  * Since `2` is not `0`, we take the second branch and calculate the factorial of `n-1`...
    * Since `1` is not `0`, we take the second branch and calculate the factorial of `n-1`...
      * Since `0` equals `0`, we take the first branch and return `1` without making an more recursive calls.
    * The return value, `1`, is multiplied by `n`, which is `1`, and the result is returned.
  * The return value, `1`, is multiplied by `n`, which is `2`, and the result is returned.
* The return value `2` is multiplied by `n`, which is `3`, and the result, `6`, becomes the return value of the function call that started the whole process.

Figure 6-1 shows what the stack diagram looks like for this sequence of function calls.
"""

# ╔═╡ 2e8091da-7618-11eb-3181-a5801b7aaacb
Drawing(width=720, height=200) do
	defs() do
        marker(id="arrow", markerWidth="10", markerHeight="10", refX="0", refY="3", orient="auto", markerUnits="strokeWidth") do
      		path(d="M0,0 L0,6 L9,3 z", fill="black")
		end
	end
	text(x=140, y=30, font_family="JuliaMono, monospace", text_anchor="end", font_size="0.85rem", font_weight=600) do
		str("Main")
	end
    rect(x=170, y=10, width=400, height=30, fill="rgb(242, 242, 242)", stroke="black")
	text(x=140, y=70, font_family="JuliaMono, monospace", text_anchor="end", font_size="0.85rem", font_weight=600) do
		str("fact")
	end
    rect(x=170, y=50, width=400, height=30, fill="rgb(242, 242, 242)", stroke="black")
	text(x=190, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("n")
	end
	text(x=210, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=240, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("3")
	end
	text(x=300, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("recurse")
	end
	text(x=370, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=400, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("2")
	end
	text(x=460, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("result")
	end
	text(x=520, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=550, y=70, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("6")
	end
	text(x=140, y=110, font_family="JuliaMono, monospace", text_anchor="end", font_size="0.85rem", font_weight=600) do
		str("fact")
	end
    rect(x=170, y=90, width=400, height=30, fill="rgb(242, 242, 242)", stroke="black")
	text(x=190, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("n")
	end
	text(x=210, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=240, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("2")
	end
	text(x=300, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("recurse")
	end
	text(x=370, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=400, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("1")
	end
	text(x=460, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("result")
	end
	text(x=520, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=550, y=110, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("2")
	end
	text(x=140, y=150, font_family="JuliaMono, monospace", text_anchor="end", font_size="0.85rem", font_weight=600) do
		str("fact")
	end
    rect(x=170, y=130, width=400, height=30, fill="rgb(242, 242, 242)", stroke="black")
	text(x=190, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("n")
	end
	text(x=210, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=240, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("1")
	end
	text(x=300, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("recurse")
	end
	text(x=370, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=400, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("1")
	end
	text(x=460, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("result")
	end
	text(x=520, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=550, y=150, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("1")
	end
	text(x=140, y=190, font_family="JuliaMono, monospace", text_anchor="end", font_size="0.85rem", font_weight=600) do
		str("fact")
	end
    rect(x=170, y=170, width=400, height=30, fill="rgb(242, 242, 242)", stroke="black")
	text(x=190, y=190, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("n")
	end
	text(x=210, y=190, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("→")
	end
	text(x=240, y=190, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("0")
	end
	path(d="M 570 50 C 595 50 595 40 580 40", stroke="black", fill="transparent", marker_end="url(#arrow)")
	text(x=600, y=50, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("6")
	end
	path(d="M 570 90 C 595 90 595 80 580 80", stroke="black", fill="transparent", marker_end="url(#arrow)")
	text(x=600, y=90, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("2")
	end
	path(d="M 570 130 C 595 130 595 120 580 120", stroke="black", fill="transparent", marker_end="url(#arrow)")
	text(x=600, y=130, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("1")
	end
	path(d="M 570 170 C 595 170 595 160 580 160", stroke="black", fill="transparent", marker_end="url(#arrow)")
	text(x=600, y=170, font_family="JuliaMono, monospace", font_size="0.85rem", font_weight=600) do
		str("1")
	end
end

# ╔═╡ 336130c4-761d-11eb-3574-3b57c12a393a
md"*Figure 6-1. Stack diagram.*"

# ╔═╡ 885ca14c-761f-11eb-072c-c9a4a2421f8f
md"""The return values are shown being passed back up the stack. In each frame, the return value is the value of result, which is the product of n and recurse.

In the last frame, the local variables recurse and result do not exist, because the branch that creates them does not run.

!!! tip
    Julia provides the function `factorial` to calculate the factorial of an integer number."""

# ╔═╡ a4c4b8a8-761f-11eb-345c-572d653d9b0b
md"""## Leap of Faith

Following the flow of execution is one way to read programs, but it can quickly become overwhelming. An alternative is what I call the "leap of faith." When you come to a function call, instead of following the flow of execution, you *assume* that the function works correctly and returns the right result.

In fact, you are already practicing this leap of faith when you use built-in functions. When you call `cos` or `exp`, you don't examine the bodies of those functions. You just assume that they work because the people who wrote the built-in functions were good programmers.

The same is true when you call one of your own functions. For example, in "Boolean Functions", we wrote a function called `isdivisible` that determines whether one number is divisible by another. Once we have convinced ourselves that this function is correct—by examining the code and testing it—we can use the function without looking at the body again.

The same is true of recursive programs. In our example, when you get to the recursive call, instead of following the flow of execution, you should assume that the recursive call works (returns the correct result) and then ask yourself, "Assuming that I can find the factorial of `n-1`, can I compute the factorial of n?" It is clear that you can, by multiplying by `n`.

Of course, it's a bit strange to assume that the function works correctly when you haven't finished writing it, but that's why it's called a leap of faith!"""

# ╔═╡ d9ce6ae4-761f-11eb-346a-df17c8a60871
md"""## One More Example

After factorial, the most common example of a recursively defined mathematical function is Fibonacci:

```math
\textit{fib}(n)=\begin{cases}
0&\textrm{if }n=0\\
1&\textrm{if }n=1\\
\textit{fib}(n-1)+\textit{fib}(n-2)&\textrm{if }n>1
\end{cases}
```

Translated into Julia, it looks like this:
"""

# ╔═╡ 98385d53-9adf-483e-befd-497996c4c80c
function fib(n)
	if n == 0
		return 0
	elseif n == 1
		return 1
	else
		return fib(n-1) + fib(n-2)
	end
end

# ╔═╡ ba23ee63-ffbb-46b8-b9df-42b6f0120418
md"""If you try to follow the flow of execution here, even for fairly small values of `n`, your head explodes. But if you take the leap of faith and you assume that the two recursive calls work correctly, then it is clear that you get the right result by adding them together.
"""

# ╔═╡ 8e7878f2-7620-11eb-058a-7346748f29b0
md"""## Checking Types

What happens if we call `fact` and give it `1.5` as an argument?
"""

# ╔═╡ 72f36258-495e-472f-9f0f-f1119b265359
fact(1.5)

# ╔═╡ f4bfd186-923b-40e7-b14d-3ccc5b3f597c
md"""It looks like an infinite recursion. How can that be? The function has a base case— when `n == 0`. But if `n` is not an integer, we can *miss* the base case and recurse forever.

In the first recursive call, the value of `n` is `0.5`. In the next, it is `-0.5`. From there, it gets smaller (more negative), but it will never be `0`.

We have two choices. We can try to generalize the factorial function to work with floating-point numbers, or we can make `fact` check the type of its argument. The first option is called the gamma function, and it's a little beyond the scope of this book. So we'll go for the second.

We can use the built-in operator `isa` to verify the type of the argument. While we're at it, we can also make sure the argument is positive:
"""

# ╔═╡ 9f7ddc22-6e1d-40da-b5bc-076a7844daa0
function fact_guard(n)
	if !(n isa Int64)
		error("Factorial is only defined for integers.")
	elseif n < 0
		error("Factorial is not defined for negative integers.")
	elseif n == 0
		return 1
	else
		return n * fact_guard(n-1)
	end
end

# ╔═╡ 355fd1d9-8939-4266-b3c1-78bb0f08ebfc
md"""The first base case handles nonintegers; the second handles negative integers. In both cases, the program prints an error message and returns nothing to indicate that something went wrong:
"""

# ╔═╡ bed7468e-b2c4-46fb-9cde-e5cdeab2a798
fact_guard("fred")

# ╔═╡ 28b64d6d-2664-4a0e-9045-0c7c2e66a7aa
fact_guard(-2)

# ╔═╡ d2efe1f2-681e-4002-9611-6b58552971fe
md"""If we get past both checks, we know that `n` is positive or `0`, so we can prove that the recursion terminates.

This program demonstrates a pattern sometimes called a guardian. The first two conditionals act as guardians, protecting the code that follows from values that might cause an error. The guardians make it possible to prove the correctness of the code.

In "Catching Exceptions" we will see a more flexible alternative to printing an error message: raising an exception.

Preferably, the first guardian should be omitted by specifying the type of the argument in the header of the function definition, see "Methods".
"""

# ╔═╡ 431b4dc0-7621-11eb-1eb8-59d8c7c61a48
md"""## Debugging

Breaking a large program into smaller functions creates natural checkpoints for debugging. If a function is not working, there are three possibilities to consider:

* There is something wrong with the arguments the function is getting; a precondition is violated.
* There is something wrong with the function; a postcondition is violated.
* There is something wrong with the return value or the way it is being used.

To rule out the first possibility, you can add a print statement at the beginning of the function and display the values of the parameters (and maybe their types). Or you can write code that checks the preconditions explicitly.

If the parameters look good, add a print statement before each return statement and display the return value. If possible, check the result by hand. Consider calling the function with values that make it easy to check the result (as in "Incremental Development").

If the function seems to be working, look at the function call to make sure the return value is being used correctly (or used at all!).

Adding print statements at the beginning and end of a function can help make the flow of execution more visible. For example, here is a version of `fact` with print statements:
"""

# ╔═╡ 2b4f7fdf-ecd8-4c06-a86e-0eafd215be68
function fact_debug(n)
	space = " " ^ (4 * n)
	println(space, "factorial ", n)
	if n == 0
		println(space, "returning 1")
		return 1
	end
	recurse = fact_debug(n-1)
	result = n * recurse
	println(space, "returning ", result)
	return result
end

# ╔═╡ 2ac4a181-fc31-4b5d-8533-0c9275eebf9d
md"""`space` is a string of space characters that controls the indentation of the output:
"""

# ╔═╡ a238ab4e-4f33-4d05-b931-a4fd1d74eaec
fact_debug(4)

# ╔═╡ 1e77e67d-dd11-41f3-ac73-da3db8dd13f2
md"""If you are confused about the flow of execution, this kind of output can be helpful. It takes some time to develop effective scaffolding, but a little bit of scaffolding can save a lot of debugging.
"""

# ╔═╡ b23efabc-7621-11eb-1d20-9959e0cda861
md"""## Glossary

*temporary variable*:
A variable used to store an intermediate value in a complex calculation.

*dead code*:
Part of a program that can never run, often because it appears after a return statement.

*incremental development*:
A program development plan intended to avoid debugging by adding and testing only a small amount of code at a time.

*scaffolding*:
Code that is used during program development but is not part of the final version.

*guardian*:
A programming pattern that uses a conditional statement to check for and handle circumstances that might cause an error."""

# ╔═╡ e30a3db6-7621-11eb-0dbd-b962759a4c5a
md"""## Exercises

#### Exercise 6-4

Draw a stack diagram for the following program. What does the program print?

```julia
function b(z)
	prod = a(z, z)
    println(z, " ", prod)
	prod
end

function a(x, y)
	x=x+1
	x*y
end

function c(x, y, z)
	total=x+y+z
	square = b(total)^2
	square
end

x=1
y=x+1
println(c(x, y+3, x+y))
```
"""

# ╔═╡ 1269fe6e-7622-11eb-3da2-df0623082981
md"""#### Exercise 6-5

The Ackermann function, ``A(m, n)``, is defined as:

```math
A(m,n)=\begin{cases}
n+1&\textrm{if }m=0\\
A(m-1,1)&\textrm{if }m>0\textrm{ and }n=0\\
A(m-1,A(m,n-1))&\textrm{if }m>0\textrm{ and }n>0
\end{cases}
```

Write a function named `ack` that evaluates the Ackermann function. Use your function to evaluate `ack(3, 4)`, which should be `125`. What happens for larger values of `m` and `n`?
"""

# ╔═╡ 80d44aee-7622-11eb-0555-e3f485a65fe9
md"""#### Exercise 6-6

A palindrome is a word that is spelled the same backward and forward, like "noon" or "redivider." Recursively, a word is a palindrome if the first and last letters are the same and the middle is a palindrome.

The following are functions that take a string argument and return the first, last, and middle letters:

```julia
function first(word)
	first = firstindex(word)
	word[first]
end

function last(word)
	last = lastindex(word)
	word[last]
end

function middle(word)
	first = firstindex(word)
	last = lastindex(word)
	word[nextind(word, first) : prevind(word, last)]
end
```

We'll see how they work in Chapter 8.

1. Test these functions out. What happens if you call `middle` with a string with two letters? One letter? What about the empty string, which is written "" and contains no letters?
2. Write a function called `ispalindrome` that takes a string argument and returns `true` if it is a palindrome and `false` otherwise. Remember that you can use the built-in function length to check the length of a string."""

# ╔═╡ cc009a36-7622-11eb-1c86-1fbb98e9fdb3
md"""#### Exercise 6-7

A number, ``a``, is a power of ``b`` if it isdivisible by ``b`` and ``\frac{a}{b}`` is a power of ``b``. Write a function called `ispower` that takes parameters `a` and `b` and returns `true` if `a` is a power of `b`.

!!! tip
    You will have to think about the base case.
"""

# ╔═╡ 260955f6-7623-11eb-332f-dbba32b4a3d9
md"""#### Exercise 6-8

The greatest common divisor (GCD) of ``a`` and ``b`` is the largest number that divides both of them with no remainder.

One way to find the GCD of two numbers is based on the observation that if ``r`` is the remainder when ``a`` is divided by ``b``, then `gcd(a, b) = gcd(b, r)`. As a base case, we can use `gcd(a, 0) = a`.

Write a function called `gcd` that takes parameters `a` and `b` and returns their greatest common divisor.

*Credit*: This exercise is based on an example from Hal Abelson and Gerald Jay Sussman's *Structure and Interpretation of Computer Programs* (MIT Press)."""

# ╔═╡ Cell order:
# ╟─32be2dac-7618-11eb-2ea5-9f165c3c91e1
# ╟─334f2774-7610-11eb-197e-eb4c20530a0c
# ╟─b1a8c332-7610-11eb-1b18-f7bf7f28ea27
# ╠═fbb22aac-ed8a-4e25-8fb7-515798a7f72d
# ╟─b96ba715-ddda-47af-9dac-407923b6d03a
# ╠═6887201f-1ebb-4201-8cd4-6f592aa12efd
# ╟─c9767a6b-ce21-4843-9bcb-330af6444fd8
# ╠═129075a2-a215-4905-8d6e-d04da70fe69a
# ╟─4e7abb20-5521-436e-a9fa-9bfd0fbdf47e
# ╠═131480f6-71d7-42a3-a7b0-a2112ef2abfe
# ╟─1a73c7ad-bc08-415a-b37f-ebe7acc8a8a9
# ╟─4219f3ac-7612-11eb-3167-f55e643f9235
# ╟─8b79bba4-7682-11eb-2ea1-0986a9911b40
# ╟─bfecb80e-7612-11eb-0633-035cbcd3e426
# ╠═e4dc510b-c45a-45ad-8f36-c173c3fd587e
# ╟─bb192f6d-32bc-4a78-8360-eba58e73b5ca
# ╠═54c72011-910e-45e9-a597-ccdc4dff6743
# ╟─e787ee70-f4d0-4e0b-a9ab-88411565eb85
# ╠═58a165a4-942b-4cf0-aabe-bc68aee3c34c
# ╟─4374af23-b021-4ac9-8bb1-5fe7fd896cf3
# ╠═bb9f9b67-d76a-4956-9fbe-6b0a934eeb0e
# ╠═4c5f679a-0a37-4279-be37-2c53fe0d925c
# ╟─f9f26b03-0cde-4428-aac5-236fb7164b34
# ╟─8d9ff285-6907-4071-b208-7d8fc702a59b
# ╟─f5edc4c2-7613-11eb-0765-cba4f0286212
# ╟─47e45c90-7615-11eb-0fe7-358b9d219497
# ╠═80890607-b4be-4541-bea0-11744cabbadb
# ╟─a74ddcba-7615-11eb-1ba0-c1d9a4eacfb5
# ╠═aa7f4b2d-a6c9-4c61-ae18-9c929ecd117e
# ╟─67568605-8fc5-4f8a-8f87-387d7663cb70
# ╠═5fa7bb83-b035-4ddf-9447-7eecfa09e952
# ╠═69a47f53-bc26-4603-a1fd-47f0ccecfffe
# ╟─cf96bc1e-a42f-42fd-a3b1-e6318da2daf0
# ╠═b292289e-4cda-4725-be1f-0b7dfc49e31d
# ╟─ef5158e3-65b4-4979-9843-1f7c8ef757bb
# ╟─3a20604e-7616-11eb-20c6-1fb57dbbb3c8
# ╟─53822bd0-7616-11eb-08df-0b6ef72120a8
# ╠═fe51d5b9-30ae-4b09-b4d0-6bd312e18df2
# ╟─aba2610e-6673-42cd-9db8-1bb14adc3c6a
# ╠═0091c836-cb15-4ecf-b001-0bafb5143c31
# ╟─dc3e37f9-d686-4e72-9b46-5fcbba041f5b
# ╠═c665c76f-1b7f-4b61-976f-c134a670fccf
# ╟─dc241e23-e6d5-4997-b7fa-1e44d66226c0
# ╟─2e8091da-7618-11eb-3181-a5801b7aaacb
# ╟─336130c4-761d-11eb-3574-3b57c12a393a
# ╟─885ca14c-761f-11eb-072c-c9a4a2421f8f
# ╟─a4c4b8a8-761f-11eb-345c-572d653d9b0b
# ╟─d9ce6ae4-761f-11eb-346a-df17c8a60871
# ╠═98385d53-9adf-483e-befd-497996c4c80c
# ╟─ba23ee63-ffbb-46b8-b9df-42b6f0120418
# ╟─8e7878f2-7620-11eb-058a-7346748f29b0
# ╠═72f36258-495e-472f-9f0f-f1119b265359
# ╟─f4bfd186-923b-40e7-b14d-3ccc5b3f597c
# ╠═9f7ddc22-6e1d-40da-b5bc-076a7844daa0
# ╟─355fd1d9-8939-4266-b3c1-78bb0f08ebfc
# ╠═bed7468e-b2c4-46fb-9cde-e5cdeab2a798
# ╠═28b64d6d-2664-4a0e-9045-0c7c2e66a7aa
# ╟─d2efe1f2-681e-4002-9611-6b58552971fe
# ╟─431b4dc0-7621-11eb-1eb8-59d8c7c61a48
# ╠═2b4f7fdf-ecd8-4c06-a86e-0eafd215be68
# ╟─2ac4a181-fc31-4b5d-8533-0c9275eebf9d
# ╠═a238ab4e-4f33-4d05-b931-a4fd1d74eaec
# ╟─1e77e67d-dd11-41f3-ac73-da3db8dd13f2
# ╟─b23efabc-7621-11eb-1d20-9959e0cda861
# ╟─e30a3db6-7621-11eb-0dbd-b962759a4c5a
# ╟─1269fe6e-7622-11eb-3da2-df0623082981
# ╟─80d44aee-7622-11eb-0555-e3f485a65fe9
# ╟─cc009a36-7622-11eb-1c86-1fbb98e9fdb3
# ╟─260955f6-7623-11eb-332f-dbba32b4a3d9


text:
<measure>
  <schema_version>3.0</schema_version>
  <name>meter_flood_plot_brushable</name>
  <uid>2c3ded96-f5a8-4f42-bf65-009c62ad3065</uid>
  <version_id>da2bb81c-891f-4cce-953d-8333e9404542</version_id>
  <xml_checksum>C46EF23F</xml_checksum>
  <class_name>MeterFloodPlotBrushable</class_name>
  <display_name>MeterFloodPlot_Brushable</display_name>
  <description>This measures generates a brushable flood plot of the requested meter.</description>
  <modeler_description>To use this measure you need to also add a measure to add the meter to the model with hourly frequency.</modeler_description>
  <arguments>
    <argument>
      <name>meter_name</name>
      <display_name>Enter Meter Name.</display_name>
      <type>String</type>
      <required>true</required>
      <model_dependent>false</model_dependent>
      <default_value>Electricity:Facility</default_value>
    </argument>
  </arguments>
  <provenances/>
  <tags>
    <tag>Reporting.QAQC</tag>
  </tags>
  <attributes>
    <attribute>
      <name>Uses SketchUp API</name>
      <value>false</value>
      <datatype>boolean</datatype>
    </attribute>
    <attribute>
      <name>Measure Type</name>
      <value>ReportingMeasure</value>
      <datatype>string</datatype>
    </attribute>
  </attributes>
  <files>
    <file>
      <filename>report.html.in</filename>
      <filetype>in</filetype>
      <usage_type>resource</usage_type>
      <checksum>4B4C11C3</checksum>
    </file>
    <file>
      <version>
        <software_program>OpenStudio</software_program>
        <identifier>1.2.0</identifier>
        <min_compatible>1.2.0</min_compatible>
      </version>
      <filename>measure.rb</filename>
      <filetype>rb</filetype>
      <usage_type>script</usage_type>
      <checksum>7EACC521</checksum>
    </file>
  </files>
</measure>

redpajama_set_name: RedPajamaGithub


text:
angular.module('app').component('editUserPref', {
    templateUrl: '/userPreferences/editUserPref.html',
    bindings: {
        userPrefData: '=userPreferences'
    },
    controller: function (fbRef, $scope, $location) {
        var ctrl = this;
        ctrl.themes = [
            "light",
            "dark"
        ];

        ctrl.userPrefData.$bindTo($scope,"$ctrl.userPreferences").then(function(){
            if(!ctrl.userPreferences.theme){
                ctrl.userPreferences.theme=ctrl.themes[0];
            }
        });

        ctrl.save = function () {
            ctrl.userPreferences.$save();
        };
        ctrl.cancel = function () {
            $location.path('/home');
        }
    }
});


text:
exports.info = { FormatID: '1073',
  FormatName: 'EndNote Import File',
  FormatVersion: '',
  FormatAliases: '',
  FormatFamilies: '',
  FormatTypes: 'Text (Structured)',
  FormatDisclosure: '',
  FormatDescription: 'This is an outline record only, and requires further details, research or authentication to provide information that will enable users to further understand the format and to assess digital preservation risks associated with it if appropriate. If you are able to help by supplying any additional information concerning this entry, please return to the main PRONOM page and select 'Add an Entry'.',
  BinaryFileFormat: 'Text',
  ByteOrders: '',
  ReleaseDate: '',
  WithdrawnDate: '',
  ProvenanceSourceID: '1',
  ProvenanceName: 'Digital Preservation Department / The National Archives',
  ProvenanceSourceDate: '31 Jan 2011',
  ProvenanceDescription: '',
  LastUpdatedDate: '31 Jan 2011',
  FormatNote: '',
  FormatRisk: '',
  TechnicalEnvironment: '',
  FileFormatIdentifier:
   [ { Identifier: 'application/x-endnote-refer',
       IdentifierType: 'MIME' },
     { Identifier: 'fmt/328', IdentifierType: 'PUID' } ],
  ExternalSignature:
   [ { ExternalSignatureID: '1080',
       Signature: 'enw',
       SignatureType: 'File extension' },
     { ExternalSignatureID: '1081',
       Signature: 'enr',
       SignatureType: 'File extension' } ],
  InternalSignature:
   [ { SignatureID: '425',
       SignatureName: 'EndNote Import File No.1',
       SignatureNote: 'The format is made up of various pieces of bibliographical data. Each piece of information is preceded by an indicator sequence which defines the type of information recorded, e.g. %A precedes author information, %D precedes date information, %T precedes title etc. This signature has been based on the relative positions of %A with %T and %D sequences, which appeared in all End Note Import files tested.',
       ByteSequence:
        { ByteSequenceID: '532',
          PositionType: 'Absolute from BOF',
          Offset: '0',
          MaxOffset: '154',
          IndirectOffsetLocation: '',
          IndirectOffsetLength: '',
          Endianness: '',
          ByteSequenceValue: '254120[41:5A]*(0A|0A0D)25(44|54)20([30:39]|[41:5A])' } },
     { SignatureID: '426',
       SignatureName: 'EndNote Import File No.2',
       SignatureNote: 'The format is made up of various pieces of bibliographical data. Each piece of information is preceded by an indicator sequence which defines the type of information recorded, e.g. %A precedes author information, %D precedes date information, %T precedes title etc. This signature has been based on the relative positions of %A and %D and %T sequences, which appeared in all End Note Import files tested.',
       ByteSequence:
        { ByteSequenceID: '533',
          PositionType: 'Absolute from BOF',
          Offset: '0',
          MaxOffset: '154',
          IndirectOffsetLocation: '',
          IndirectOffsetLength: '',
          Endianness: '',
          ByteSequenceValue: '2541[41:5A]*(0A|0A0D)25(44|54)([30:39]|[41:5A])' } } ],
  RelatedFormat:
   [ { RelationshipType: 'Has lower priority than',
       RelatedFormatID: '86',
       RelatedFormatName: 'Encapsulated PostScript File Format',
       RelatedFormatVersion: '1.2' },
     { RelationshipType: 'Has lower priority than',
       RelatedFormatID: '138',
       RelatedFormatName: 'Postscript',
       RelatedFormatVersion: '1.0' },
     { RelationshipType: 'Has lower priority than',
       RelatedFormatID: '331',
       RelatedFormatName: 'Encapsulated PostScript File Format',
       RelatedFormatVersion: '3' },
     { RelationshipType: 'Has lower priority than',
       RelatedFormatID: '332',
       RelatedFormatName: 'Encapsulated PostScript File Format',
       RelatedFormatVersion: '2.0' },
     { RelationshipType: 'Has lower priority than',
       RelatedFormatID: '771',
       RelatedFormatName: 'PostScript',
       RelatedFormatVersion: '2.0' },
     { RelationshipType: 'Has lower priority than',
       RelatedFormatID: '772',
       RelatedFormatName: 'PostScript',
       RelatedFormatVersion: '2.1' },
     { RelationshipType: 'Has lower priority than',
       RelatedFormatID: '773',
       RelatedFormatName: 'PostScript',
       RelatedFormatVersion: '3.0' },
     { RelationshipType: 'Has lower priority than',
       RelatedFormatID: '1288',
       RelatedFormatName: 'PostScript',
       RelatedFormatVersion: '3.1' } ] }


text:
package com.genesis.hamlet.ui.users;

import android.content.Context;

import com.genesis.hamlet.data.models.user.User;
import com.genesis.hamlet.util.mvp.IBasePresenter;
import com.genesis.hamlet.util.mvp.IBaseView;

import java.util.List;

/**
 * The interface that exposes the functionalities of a Photo View and Presenter
 */
interface UsersContract {

    interface View extends IBaseView {
        void showUsers(List<User> users);
        void addUser(User user);
        void updateUser(User user);
        void shouldShowPlaceholderText();
        void remove(User user);
    }

    interface Presenter extends IBasePresenter<View> {
        boolean isConnected();
        void connect(Context context);
        void loadMoreUsers(Context context, int page);
        void interestsUpdated(Context context);
    }
}


text:
pinewall is translating

[Anatomy of a Linux DNS Lookup – Part IV][2]
============================================

In [Anatomy of a Linux DNS Lookup – Part I][3], [Part II][4], and [Part III][5] I covered:

*   `nsswitch`

*   `/etc/hosts`

*   `/etc/resolv.conf`

*   `ping` vs `host` style lookups

*   `systemd` and its `networking` service

*   `ifup` and `ifdown`

*   `dhclient`

*   `resolvconf`

*   `NetworkManager`

*   `dnsmasq`

In Part IV I'll cover how containers do DNS. Yes, that's not simple either…

* * *

1) Docker and DNS
============================================================

In [part III][6] we looked at DNSMasq, and learned that it works by directing DNS queries to the localhost address `127.0.0.1`, and a process listening on port 53 there will accept the request.

So when you run up a Docker container, on a host set up like this, what do you expect to see in its `/etc/resolv.conf`?

Have a think, and try and guess what it will be.

Here's the default output if you run a default Docker setup:

```
$  docker run  ubuntu cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
# 127.0.0.53 is the systemd-resolved stub resolver.
# run "systemd-resolve --status" to see details about the actual nameservers.

search home
nameserver 8.8.8.8
nameserver 8.8.4.4
```

Hmmm.

#### Where did the addresses `8.8.8.8` and `8.8.4.4` come from?

When I pondered this question, my first thought was that the container would inherit the `/etc/resolv.conf` settings from the host. But a little thought shows that that won't always work.

If you have DNSmasq set up on the host, the `/etc/resolv.conf` file will be pointed at the `127.0.0.1` loopback address. If this were passed through to the container, the container would look up DNS addresses from within its own networking context, and there's no DNS server available within the container context, so the DNS lookups would fail.

'A-ha!' you might think: we can always use the host's DNS server by using the  _host's_  IP address, available from within the container as the default route:

```
root@79a95170e679:/# ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
```

#### Use the host?

From that we can work out that the 'host' is on the ip address: `172.17.0.1`, so we could try manually pointing DNS at that using dig (you could also update the `/etc/resolv.conf` and then run `ping`, this just seems like a good time to introduce `dig` and its `@` flag, which points the request at the ip address you specify):

```
root@79a95170e679:/# dig @172.17.0.1 google.com | grep -A1 ANSWER.SECTION
;; ANSWER SECTION:
google.com.             112     IN      A       172.217.23.14
```

However: that might work if you use DNSMasq, but if you don't it won't, as there's no DNS server on the host to look up.

So Docker's solution to this quandary is to bypass all that complexity and point your DNS lookups to Google's DNS servers at `8.8.8.8` and `8.8.4.4`, ignoring whatever the host context is.

 _Anecdote: This was the source of my first problem with Docker back in 2013\. Our corporate network blocked access to those IP addresses, so my containers couldn't resolve URLs._

So that's Docker containers, but container  _orchestrators_  such as Kubernetes can do different things again…

# 2) Kubernetes and DNS

The unit of container deployment in Kubernetes is a Pod. A pod is a set of co-located containers that (among other things) share the same IP address.

An extra challenge with Kubernetes is to forward requests for Kubernetes services to the right resolver (eg `myservice.kubernetes.io`) to the private network allocated to those service addresses. These addresses are said to be on the 'cluster domain'. This cluster domain is configurable by the administrator, so it might be `cluster.local` or `myorg.badger` depending on the configuration you set up.

In Kubernetes you have four options for configuring how DNS lookup works within your pod.

*   Default

This (misleadingly-named) option takes the same DNS resolution path as the host the pod runs on, as in the 'naive' DNS lookup described earlier. It's misleadingly named because it's not the default! ClusterFirst is.

If you want to override the `/etc/resolv.conf` entries, you can in your config for the kubelet.

*   ClusterFirst

ClusterFirst does selective forwarding on the DNS request. This is achieved in one of two ways based on the configuration.

In the first, older and simpler setup, a rule was followed where if the cluster domain was not found in the request, then it was forwarded to the host.

In the second, newer approach, you can configure selective forwarding on an internal DNS

Here's what the config looks like and a diagram lifted from the [Kubernetes docs][7] which shows the flow:

```
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {"acme.local": ["1.2.3.4"]}
  upstreamNameservers: |
    ["8.8.8.8", "8.8.4.4"]
```

The `stubDomains` entry defines specific DNS servers to use for specific domains. The upstream servers are the servers we defer to when nothing else has picked up the DNS request.

This is achieved with our old friend DNSMasq running in a pod.

![kubedns](https://zwischenzugs.files.wordpress.com/2018/08/kubedns.png?w=525)

The other two options are more niche:

*   ClusterFirstWithHostNet

This applies if you use host network for your pods, ie you bypass the Docker networking setup to use the same network as you would directly on the host the pod is running on.

*   None

None does nothing to DNS but forces you to specify the DNS settings in the `dnsConfig` field in the pod specification.

### CoreDNS Coming

And if that wasn't enough, this is set to change again as CoreDNS comes to Kubernetes, replacing kube-dns. CoreDNS will offer a few benefits over kube-dns, being more configurabe and more efficient.

Find out more [here][8].

If you're interested in OpenShift networking, I wrote a post on that [here][9]. But that was for 3.6 so is likely out of date now.

### End of Part IV

That's part IV done. In it we covered.

*   Docker DNS lookups

*   Kubernetes DNS lookups

*   Selective forwarding (stub domains)

*   kube-dns

--------------------------------------------------------------------------------

via: https://zwischenzugs.com/2018/08/06/anatomy-of-a-linux-dns-lookup-part-iv/

作者:[zwischenzugs][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

[a]:https://zwischenzugs.com/
[1]:https://zwischenzugs.com/2018/08/06/anatomy-of-a-linux-dns-lookup-part-iv/
[2]:https://zwischenzugs.com/2018/08/06/anatomy-of-a-linux-dns-lookup-part-iv/
[3]:https://zwischenzugs.com/2018/06/08/anatomy-of-a-linux-dns-lookup-part-i/
[4]:https://zwischenzugs.com/2018/06/18/anatomy-of-a-linux-dns-lookup-part-ii/
[5]:https://zwischenzugs.com/2018/07/06/anatomy-of-a-linux-dns-lookup-part-iii/
[6]:https://zwischenzugs.com/2018/07/06/anatomy-of-a-linux-dns-lookup-part-iii/
[7]:https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#impacts-on-pods
[8]:https://coredns.io/
[9]:https://zwischenzugs.com/2017/10/21/openshift-3-6-dns-in-pictures/


text:
package de.uni_mannheim.informatik.dws.winter.datafusion.conflictresolution.date;

import de.uni_mannheim.informatik.dws.winter.datafusion.conflictresolution.numeric.Maximum;
import de.uni_mannheim.informatik.dws.winter.model.FusedValue;
import de.uni_mannheim.informatik.dws.winter.model.FusibleValue;
import de.uni_mannheim.informatik.dws.winter.model.defaultmodel.Attribute;
import de.uni_mannheim.informatik.dws.winter.model.defaultmodel.Record;
import junit.framework.TestCase;
import org.junit.Test;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.LinkedList;

public class EarliestDateTest extends TestCase {

    @Test
    public void testResolveConflict() {
        // Setup
        Collection<FusibleValue<LocalDateTime, Record, Attribute>> values = new LinkedList<>();
        EarliestDate<Record,Attribute> earliestDate = new EarliestDate<>();

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        LocalDateTime firstDate = LocalDateTime.parse("2020-01-01 12:30", formatter);
        LocalDateTime secondDate = LocalDateTime.parse("2020-01-02 10:30", formatter);
        LocalDateTime thirdDate = LocalDateTime.parse("2021-01-01 09:30", formatter);

        // Run Tests
        FusedValue<LocalDateTime, Record, Attribute> result = earliestDate.resolveConflict(values);
        assertNull(result.getValue());

        values.add(new FusibleValue<>(firstDate, null, null));
        result = earliestDate.resolveConflict(values);
        assertEquals(firstDate, result.getValue());

        values.add(new FusibleValue<>(secondDate, null, null));
        result = earliestDate.resolveConflict(values);
        assertEquals(firstDate, result.getValue());

        values.add(new FusibleValue<>(thirdDate, null, null));
        result = earliestDate.resolveConflict(values);
        assertEquals(firstDate, result.getValue());
    }

}


text:
namespace osrm
{
namespace extractor
{

// OSM offers two types of restrictions, via node and via-way restrictions. We parse both into the
// same input container
//
// A restriction turning at a single node. This is the most common type of restriction:
//
// a - b - c
//     |
//     d
//
// ab via b to bd
struct InputNodeRestriction
{
    OSMWayID from;
    OSMNodeID via;
    OSMWayID to;
};

// A restriction that uses a single via-way in between
//
// f - e - d
//     |
// a - b - c
//
// ab via be to ef -- no u turn
struct InputWayRestriction
{
    OSMWayID from;
    OSMWayID via;
    OSMWayID to;
};

// Outside view of the variant, these are equal to the `which()` results
enum RestrictionType
{
    NODE_RESTRICTION = 0,
    WAY_RESTRICTION = 1,
    NUM_RESTRICTION_TYPES = 2
};

struct InputTurnRestriction
{
    // keep in the same order as the turn restrictions below
    mapbox::util::variant<InputNodeRestriction, InputWayRestriction> node_or_way;
    bool is_only;

    OSMWayID From() const
    {
        return node_or_way.which() == RestrictionType::NODE_RESTRICTION
                   ? mapbox::util::get<InputNodeRestriction>(node_or_way).from
                   : mapbox::util::get<InputWayRestriction>(node_or_way).from;
    }

    OSMWayID To() const
    {
        return node_or_way.which() == RestrictionType::NODE_RESTRICTION
                   ? mapbox::util::get<InputNodeRestriction>(node_or_way).to
                   : mapbox::util::get<InputWayRestriction>(node_or_way).to;
    }

    RestrictionType Type() const
    {
        BOOST_ASSERT(node_or_way.which() < RestrictionType::NUM_RESTRICTION_TYPES);
        return static_cast<RestrictionType>(node_or_way.which());
    }

    InputWayRestriction &AsWayRestriction()
    {
        BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
        return mapbox::util::get<InputWayRestriction>(node_or_way);
    }

    const InputWayRestriction &AsWayRestriction() const
    {
        BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
        return mapbox::util::get<InputWayRestriction>(node_or_way);
    }

    InputNodeRestriction &AsNodeRestriction()
    {
        BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
        return mapbox::util::get<InputNodeRestriction>(node_or_way);
    }

    const InputNodeRestriction &AsNodeRestriction() const
    {
        BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
        return mapbox::util::get<InputNodeRestriction>(node_or_way);
    }
};
struct InputConditionalTurnRestriction : InputTurnRestriction
{
    std::vector<util::OpeningHours> condition;
};

// OSRM manages restrictions based on node IDs which refer to the last node along the edge. Note
// that this has the side-effect of not allowing parallel edges!
struct NodeRestriction
{
    NodeID from;
    NodeID via;
    NodeID to;

    // check if all parts of the restriction reference an actual node
    bool Valid() const
    {
        return from != SPECIAL_NODEID && to != SPECIAL_NODEID && via != SPECIAL_NODEID;
    };

    bool operator==(const NodeRestriction &other) const
    {
        return std::tie(from, via, to) == std::tie(other.from, other.via, other.to);
    }
};

// A way restriction in the context of OSRM requires translation into NodeIDs. This is due to the
// compression happening in the graph creation process which would make it difficult to track
// way-ids over a series of operations. Having access to the nodes directly allows look-up of the
// edges in the processed structures
struct WayRestriction
{
    // a way restriction in OSRM is essentially a dual node turn restriction;
    //
    // |     |
    // c -x- b
    // |     |
    // d     a
    //
    // from ab via bxc to cd: no_uturn
    //
    // Technically, we would need only a,b,c,d to describe the full turn in terms of nodes. When
    // parsing the relation, though, we do not know about the final representation in the node-based
    // graph for the restriction. In case of a traffic light, for example, we might end up with bxc
    // not being compressed to bc. For that reason, we need to maintain two node restrictions in
    // case a way restrction is not fully collapsed
    NodeRestriction in_restriction;
    NodeRestriction out_restriction;

    bool operator==(const WayRestriction &other) const
    {
        return std::tie(in_restriction, out_restriction) ==
               std::tie(other.in_restriction, other.out_restriction);
    }
};

// Wrapper for turn restrictions that gives more information on its type / handles the switch
// between node/way/multi-way restrictions
struct TurnRestriction
{
    // keep in the same order as the turn restrictions above
    mapbox::util::variant<NodeRestriction, WayRestriction> node_or_way;
    bool is_only;

    // construction for NodeRestrictions
    explicit TurnRestriction(NodeRestriction node_restriction, bool is_only = false)
        : node_or_way(node_restriction), is_only(is_only)
    {
    }

    // construction for WayRestrictions
    explicit TurnRestriction(WayRestriction way_restriction, bool is_only = false)
        : node_or_way(way_restriction), is_only(is_only)
    {
    }

    explicit TurnRestriction()
    {
        node_or_way = NodeRestriction{SPECIAL_EDGEID, SPECIAL_NODEID, SPECIAL_EDGEID};
    }

    WayRestriction &AsWayRestriction()
    {
        BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
        return mapbox::util::get<WayRestriction>(node_or_way);
    }

    const WayRestriction &AsWayRestriction() const
    {
        BOOST_ASSERT(node_or_way.which() == RestrictionType::WAY_RESTRICTION);
        return mapbox::util::get<WayRestriction>(node_or_way);
    }

    NodeRestriction &AsNodeRestriction()
    {
        BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
        return mapbox::util::get<NodeRestriction>(node_or_way);
    }

    const NodeRestriction &AsNodeRestriction() const
    {
        BOOST_ASSERT(node_or_way.which() == RestrictionType::NODE_RESTRICTION);
        return mapbox::util::get<NodeRestriction>(node_or_way);
    }

    RestrictionType Type() const
    {
        BOOST_ASSERT(node_or_way.which() < RestrictionType::NUM_RESTRICTION_TYPES);
        return static_cast<RestrictionType>(node_or_way.which());
    }

    // check if all elements of the edge are considered valid
    bool Valid() const
    {
        if (node_or_way.which() == RestrictionType::WAY_RESTRICTION)
        {
            auto const &restriction = AsWayRestriction();
            return restriction.in_restriction.Valid() && restriction.out_restriction.Valid();
        }
        else
        {
            auto const &restriction = AsNodeRestriction();
            return restriction.Valid();
        }
    }

    bool operator==(const TurnRestriction &other) const
    {
        if (is_only != other.is_only)
            return false;

        if (Type() != other.Type())
            return false;

        if (Type() == RestrictionType::WAY_RESTRICTION)
        {
            return AsWayRestriction() == other.AsWayRestriction();
        }
        else
        {
            return AsNodeRestriction() == other.AsNodeRestriction();
        }
    }
};

struct ConditionalTurnRestriction : TurnRestriction
{
    std::vector<util::OpeningHours> condition;
};
}
}

#endif // RESTRICTION_HPP


text:
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stddef.h>
#include <stdint.h>

#include <string>
#include <tuple>

#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h"
#include "base/files/scoped_temp_dir.h"
#include "build/build_config.h"
#include "sql/database.h"
#include "sql/statement.h"
#include "sql/test/scoped_error_expecter.h"
#include "sql/test/test_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/sqlite/sqlite3.h"

#if BUILDFLAG(IS_APPLE)
#include "base/mac/backup_util.h"
#endif

// Test that certain features are/are-not enabled in our SQLite.

namespace sql {
namespace {

using sql::test::ExecuteWithResult;
using sql::test::ExecuteWithResults;

}  // namespace

class SQLiteFeaturesTest : public testing::Test {
 public:
  ~SQLiteFeaturesTest() override = default;

  void SetUp() override {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    db_path_ = temp_dir_.GetPath().AppendASCII("sqlite_features_test.sqlite");
    ASSERT_TRUE(db_.Open(db_path_));
  }

  bool Reopen() {
    db_.Close();
    return db_.Open(db_path_);
  }

 protected:
  base::ScopedTempDir temp_dir_;
  base::FilePath db_path_;
  Database db_;

  // The error code of the most recent error.
  int error_ = SQLITE_OK;
  // Original statement which has caused the error.
  std::string sql_text_;
};

// Do not include fts1 support, it is not useful, and nobody is
// looking at it.
TEST_F(SQLiteFeaturesTest, NoFTS1) {
  sql::test::ScopedErrorExpecter expecter;
  expecter.ExpectError(SQLITE_ERROR);
  EXPECT_FALSE(db_.Execute("CREATE VIRTUAL TABLE foo USING fts1(x)"));
  EXPECT_TRUE(expecter.SawExpectedErrors());
}

// Do not include fts2 support, it is not useful, and nobody is
// looking at it.
TEST_F(SQLiteFeaturesTest, NoFTS2) {
  sql::test::ScopedErrorExpecter expecter;
  expecter.ExpectError(SQLITE_ERROR);
  EXPECT_FALSE(db_.Execute("CREATE VIRTUAL TABLE foo USING fts2(x)"));
  EXPECT_TRUE(expecter.SawExpectedErrors());
}

// fts3 is exposed in WebSQL.
TEST_F(SQLiteFeaturesTest, FTS3) {
  EXPECT_TRUE(db_.Execute("CREATE VIRTUAL TABLE foo USING fts3(x)"));
}

// Originally history used fts2, which Chromium patched to treat "foo*" as a
// prefix search, though the icu tokenizer would return it as two tokens {"foo",
// "*"}.  Test that fts3 works correctly.
TEST_F(SQLiteFeaturesTest, FTS3_Prefix) {
  db_.Close();
  sql::Database db({.enable_virtual_tables_discouraged = true});
  ASSERT_TRUE(db.Open(db_path_));

  static constexpr char kCreateSql[] =
      "CREATE VIRTUAL TABLE foo USING fts3(x, tokenize icu)";
  ASSERT_TRUE(db.Execute(kCreateSql));

  ASSERT_TRUE(db.Execute("INSERT INTO foo (x) VALUES ('test')"));

  EXPECT_EQ("test",
            ExecuteWithResult(&db, "SELECT x FROM foo WHERE x MATCH 'te*'"));
}

// Verify that Chromium's SQLite is compiled with HAVE_USLEEP defined.  With
// HAVE_USLEEP, SQLite uses usleep() with millisecond granularity.  Otherwise it
// uses sleep() with second granularity.
TEST_F(SQLiteFeaturesTest, UsesUsleep) {
  base::TimeTicks before = base::TimeTicks::Now();
  sqlite3_sleep(1);
  base::TimeDelta delta = base::TimeTicks::Now() - before;

  // It is not impossible for this to be over 1000 if things are compiled
  // correctly, but that is very unlikely.  Most platforms seem to be exactly
  // 1ms, with the rest at 2ms, and the worst observed cases was ASAN at 7ms.
  EXPECT_LT(delta.InMilliseconds(), 1000);
}

// Ensure that our SQLite version has working foreign key support with cascade
// delete support.
TEST_F(SQLiteFeaturesTest, ForeignKeySupport) {
  ASSERT_TRUE(db_.Execute("PRAGMA foreign_keys=1"));
  ASSERT_TRUE(db_.Execute("CREATE TABLE parents (id INTEGER PRIMARY KEY)"));
  ASSERT_TRUE(db_.Execute(
      "CREATE TABLE children ("
      "    id INTEGER PRIMARY KEY,"
      "    pid INTEGER NOT NULL REFERENCES parents(id) ON DELETE CASCADE)"));
  static const char kSelectParentsSql[] = "SELECT * FROM parents ORDER BY id";
  static const char kSelectChildrenSql[] = "SELECT * FROM children ORDER BY id";

  // Inserting without a matching parent should fail with constraint violation.
  EXPECT_EQ("", ExecuteWithResult(&db_, kSelectParentsSql));
  {
    sql::test::ScopedErrorExpecter expecter;
    expecter.ExpectError(SQLITE_CONSTRAINT | SQLITE_CONSTRAINT_FOREIGNKEY);
    EXPECT_FALSE(db_.Execute("INSERT INTO children VALUES (10, 1)"));
    EXPECT_TRUE(expecter.SawExpectedErrors());
  }
  EXPECT_EQ("", ExecuteWithResult(&db_, kSelectChildrenSql));

  // Inserting with a matching parent should work.
  ASSERT_TRUE(db_.Execute("INSERT INTO parents VALUES (1)"));
  EXPECT_EQ("1", ExecuteWithResults(&db_, kSelectParentsSql, "|", "\n"));
  EXPECT_TRUE(db_.Execute("INSERT INTO children VALUES (11, 1)"));
  EXPECT_TRUE(db_.Execute("INSERT INTO children VALUES (12, 1)"));
  EXPECT_EQ("11|1\n12|1",
            ExecuteWithResults(&db_, kSelectChildrenSql, "|", "\n"));

  // Deleting the parent should cascade, deleting the children as well.
  ASSERT_TRUE(db_.Execute("DELETE FROM parents"));
  EXPECT_EQ("", ExecuteWithResult(&db_, kSelectParentsSql));
  EXPECT_EQ("", ExecuteWithResult(&db_, kSelectChildrenSql));
}

// Ensure that our SQLite version supports booleans.
TEST_F(SQLiteFeaturesTest, BooleanSupport) {
  ASSERT_TRUE(
      db_.Execute("CREATE TABLE flags ("
                  "    id INTEGER PRIMARY KEY,"
                  "    true_flag BOOL NOT NULL DEFAULT TRUE,"
                  "    false_flag BOOL NOT NULL DEFAULT FALSE)"));
  ASSERT_TRUE(db_.Execute(
      "ALTER TABLE flags ADD COLUMN true_flag2 BOOL NOT NULL DEFAULT TRUE"));
  ASSERT_TRUE(db_.Execute(
      "ALTER TABLE flags ADD COLUMN false_flag2 BOOL NOT NULL DEFAULT FALSE"));
  ASSERT_TRUE(db_.Execute("INSERT INTO flags (id) VALUES (1)"));

  sql::Statement s(db_.GetUniqueStatement(
      "SELECT true_flag, false_flag, true_flag2, false_flag2"
      "    FROM flags WHERE id=1;"));
  ASSERT_TRUE(s.Step());

  EXPECT_TRUE(s.ColumnBool(0)) << " default TRUE at table creation time";
  EXPECT_TRUE(!s.ColumnBool(1)) << " default FALSE at table creation time";

  EXPECT_TRUE(s.ColumnBool(2)) << " default TRUE added by altering the table";
  EXPECT_TRUE(!s.ColumnBool(3)) << " default FALSE added by altering the table";
}

TEST_F(SQLiteFeaturesTest, IcuEnabled) {
  sql::Statement lower_en(db_.GetUniqueStatement("SELECT lower('I', 'en_us')"));
  ASSERT_TRUE(lower_en.Step());
  EXPECT_EQ("i", lower_en.ColumnString(0));

  sql::Statement lower_tr(db_.GetUniqueStatement("SELECT lower('I', 'tr_tr')"));
  ASSERT_TRUE(lower_tr.Step());
  EXPECT_EQ("\u0131", lower_tr.ColumnString(0));
}

// Verify that OS file writes are reflected in the memory mapping of a
// memory-mapped file.  Normally SQLite writes to memory-mapped files using
// memcpy(), which should stay consistent.  Our SQLite is slightly patched to
// mmap read only, then write using OS file writes.  If the memory-mapped
// version doesn't reflect the OS file writes, SQLite's memory-mapped I/O should
// be disabled on this platform using SQLITE_MAX_MMAP_SIZE=0.
TEST_F(SQLiteFeaturesTest, Mmap) {
  // Try to turn on mmap'ed I/O.
  std::ignore = db_.Execute("PRAGMA mmap_size = 1048576");
  {
    sql::Statement s(db_.GetUniqueStatement("PRAGMA mmap_size"));

    ASSERT_TRUE(s.Step());
    ASSERT_GT(s.ColumnInt64(0), 0);
  }
  db_.Close();

  const uint32_t kFlags =
      base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE;
  char buf[4096];

  // Create a file with a block of '0', a block of '1', and a block of '2'.
  {
    base::File f(db_path_, kFlags);
    ASSERT_TRUE(f.IsValid());
    memset(buf, '0', sizeof(buf));
    ASSERT_EQ(f.Write(0*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf));

    memset(buf, '1', sizeof(buf));
    ASSERT_EQ(f.Write(1*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf));

    memset(buf, '2', sizeof(buf));
    ASSERT_EQ(f.Write(2*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf));
  }

  // mmap the file and verify that everything looks right.
  {
    base::MemoryMappedFile m;
    ASSERT_TRUE(m.Initialize(db_path_));

    memset(buf, '0', sizeof(buf));
    ASSERT_EQ(0, memcmp(buf, m.data() + 0*sizeof(buf), sizeof(buf)));

    memset(buf, '1', sizeof(buf));
    ASSERT_EQ(0, memcmp(buf, m.data() + 1*sizeof(buf), sizeof(buf)));

    memset(buf, '2', sizeof(buf));
    ASSERT_EQ(0, memcmp(buf, m.data() + 2*sizeof(buf), sizeof(buf)));

    // Scribble some '3' into the first page of the file, and verify that it
    // looks the same in the memory mapping.
    {
      base::File f(db_path_, kFlags);
      ASSERT_TRUE(f.IsValid());
      memset(buf, '3', sizeof(buf));
      ASSERT_EQ(f.Write(0*sizeof(buf), buf, sizeof(buf)), (int)sizeof(buf));
    }
    ASSERT_EQ(0, memcmp(buf, m.data() + 0*sizeof(buf), sizeof(buf)));

    // Repeat with a single '4' in case page-sized blocks are different.
    const size_t kOffset = 1*sizeof(buf) + 123;
    ASSERT_NE('4', m.data()[kOffset]);
    {
      base::File f(db_path_, kFlags);
      ASSERT_TRUE(f.IsValid());
      buf[0] = '4';
      ASSERT_EQ(f.Write(kOffset, buf, 1), 1);
    }
    ASSERT_EQ('4', m.data()[kOffset]);
  }
}

// Verify that http://crbug.com/248608 is fixed.  In this bug, the
// compiled regular expression is effectively cached with the prepared
// statement, causing errors if the regular expression is rebound.
TEST_F(SQLiteFeaturesTest, CachedRegexp) {
  ASSERT_TRUE(db_.Execute("CREATE TABLE r (id INTEGER UNIQUE, x TEXT)"));
  ASSERT_TRUE(db_.Execute("INSERT INTO r VALUES (1, 'this is a test')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO r VALUES (2, 'that was a test')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO r VALUES (3, 'this is a stickup')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO r VALUES (4, 'that sucks')"));

  static const char kSimpleSql[] = "SELECT SUM(id) FROM r WHERE x REGEXP ?";
  sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, kSimpleSql));

  s.BindString(0, "this.*");
  ASSERT_TRUE(s.Step());
  EXPECT_EQ(4, s.ColumnInt(0));

  s.Reset(true);
  s.BindString(0, "that.*");
  ASSERT_TRUE(s.Step());
  EXPECT_EQ(6, s.ColumnInt(0));

  s.Reset(true);
  s.BindString(0, ".*test");
  ASSERT_TRUE(s.Step());
  EXPECT_EQ(3, s.ColumnInt(0));

  s.Reset(true);
  s.BindString(0, ".* s[a-z]+");
  ASSERT_TRUE(s.Step());
  EXPECT_EQ(7, s.ColumnInt(0));
}

TEST_F(SQLiteFeaturesTest, JsonIsDisabled) {
  static constexpr char kCreateSql[] =
      "CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL, data TEXT NOT NULL)";
  ASSERT_TRUE(db_.Execute(kCreateSql));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows(data) VALUES('{\"a\": 1}')"));

  {
    sql::test::ScopedErrorExpecter expecter;
    expecter.ExpectError(SQLITE_ERROR);
    EXPECT_FALSE(db_.Execute("SELECT data -> '$.a' FROM rows"));
    EXPECT_TRUE(expecter.SawExpectedErrors());
  }
}

TEST_F(SQLiteFeaturesTest, WindowFunctionsAreDisabled) {
  static constexpr char kCreateSql[] =
      "CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL, data TEXT NOT NULL)";
  ASSERT_TRUE(db_.Execute(kCreateSql));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows(id, data) VALUES(1, 'a')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows(id, data) VALUES(2, 'c')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows(id, data) VALUES(3, 'b')"));

  {
    sql::test::ScopedErrorExpecter expecter;
    expecter.ExpectError(SQLITE_ERROR);
    EXPECT_FALSE(db_.Execute(
        "SELECT data, row_number() OVER (ORDER BY data) AS rank FROM rows "
        "ORDER BY id"));
    EXPECT_TRUE(expecter.SawExpectedErrors());
  }
}

// The "No Isolation Between Operations On The Same Database Connection" section
// in https://sqlite.org/isolation.html implies that it's safe to issue multiple
// concurrent SELECTs against the same area.
//
// Chrome code is allowed to rely on this guarantee. So, we test for it here, to
// catch any regressions introduced by SQLite upgrades.
TEST_F(SQLiteFeaturesTest, ConcurrentSelects) {
  ASSERT_TRUE(db_.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY, t TEXT)"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(2, 'two')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(3, 'three')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(4, 'four')"));

  static const char kSelectAllSql[] = "SELECT id,t FROM rows";
  static const char kSelectEvenSql[] = "SELECT id,t FROM rows WHERE id%2=0";

  sql::Statement select1(db_.GetCachedStatement(SQL_FROM_HERE, kSelectEvenSql));
  sql::Statement select2(db_.GetCachedStatement(SQL_FROM_HERE, kSelectEvenSql));
  sql::Statement select3(db_.GetCachedStatement(SQL_FROM_HERE, kSelectAllSql));

  ASSERT_TRUE(select1.Step());
  EXPECT_EQ(select1.ColumnInt(0), 2);
  EXPECT_EQ(select1.ColumnString(1), "two");

  ASSERT_TRUE(select2.Step());
  EXPECT_EQ(select2.ColumnInt(0), 2);
  EXPECT_EQ(select2.ColumnString(1), "two");

  ASSERT_TRUE(select3.Step());
  EXPECT_EQ(select3.ColumnInt(0), 2);
  EXPECT_EQ(select3.ColumnString(1), "two");

  ASSERT_TRUE(select1.Step());
  EXPECT_EQ(select1.ColumnInt(0), 4);
  EXPECT_EQ(select1.ColumnString(1), "four");

  ASSERT_TRUE(select3.Step());
  EXPECT_EQ(select3.ColumnInt(0), 3);
  EXPECT_EQ(select3.ColumnString(1), "three");

  ASSERT_TRUE(select2.Step());
  EXPECT_EQ(select2.ColumnInt(0), 4);
  EXPECT_EQ(select2.ColumnString(1), "four");

  EXPECT_FALSE(select2.Step());

  ASSERT_TRUE(select3.Step());
  EXPECT_EQ(select3.ColumnInt(0), 4);
  EXPECT_EQ(select3.ColumnString(1), "four");

  select2.Reset(/*clear_bound_vars=*/true);
  ASSERT_TRUE(select2.Step());
  EXPECT_EQ(select2.ColumnInt(0), 2);
  EXPECT_EQ(select2.ColumnString(1), "two");

  EXPECT_FALSE(select1.Step());
}

// The "No Isolation Between Operations On The Same Database Connection" section
// in https://sqlite.org/isolation.html states that it's safe to DELETE a row
// that was just returned by sqlite_step() executing a SELECT statement.
//
// Chrome code is allowed to rely on this guarantee. So, we test for it here, to
// catch any regressions introduced by SQLite upgrades.
TEST_F(SQLiteFeaturesTest, DeleteCurrentlySelectedRow) {
  ASSERT_TRUE(db_.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY, t TEXT)"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(2, 'two')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(3, 'three')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(4, 'four')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(5, 'five')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(6, 'six')"));

  static const char kSelectEvenSql[] = "SELECT id,t FROM rows WHERE id%2=0";
  sql::Statement select(db_.GetCachedStatement(SQL_FROM_HERE, kSelectEvenSql));

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 2);
  ASSERT_EQ(select.ColumnString(1), "two");
  ASSERT_TRUE(db_.Execute("DELETE FROM rows WHERE id=2"));

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 4);
  ASSERT_EQ(select.ColumnString(1), "four");
  ASSERT_TRUE(db_.Execute("DELETE FROM rows WHERE id=4"));

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 6);
  ASSERT_EQ(select.ColumnString(1), "six");
  ASSERT_TRUE(db_.Execute("DELETE FROM rows WHERE id=6"));

  EXPECT_FALSE(select.Step());

  // Check that the DELETEs were applied as expected.

  static const char kSelectAllSql[] = "SELECT id,t FROM rows";
  sql::Statement select_all(
      db_.GetCachedStatement(SQL_FROM_HERE, kSelectAllSql));
  std::vector<int> remaining_ids;
  std::vector<std::string> remaining_texts;
  while (select_all.Step()) {
    remaining_ids.push_back(select_all.ColumnInt(0));
    remaining_texts.push_back(select_all.ColumnString(1));
  }

  std::vector<int> expected_remaining_ids = {3, 5};
  EXPECT_EQ(expected_remaining_ids, remaining_ids);
  std::vector<std::string> expected_remaining_texts = {"three", "five"};
  EXPECT_EQ(expected_remaining_texts, remaining_texts);
}

// The "No Isolation Between Operations On The Same Database Connection" section
// in https://sqlite.org/isolation.html states that it's safe to DELETE a row
// that was previously by sqlite_step() executing a SELECT statement.
//
// Chrome code is allowed to rely on this guarantee. So, we test for it here, to
// catch any regressions introduced by SQLite upgrades.
TEST_F(SQLiteFeaturesTest, DeletePreviouslySelectedRows) {
  ASSERT_TRUE(db_.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY, t TEXT)"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(2, 'two')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(3, 'three')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(4, 'four')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(5, 'five')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO rows VALUES(6, 'six')"));

  static const char kSelectEvenSql[] = "SELECT id,t FROM rows WHERE id%2=0";
  sql::Statement select(db_.GetCachedStatement(SQL_FROM_HERE, kSelectEvenSql));

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 2);
  ASSERT_EQ(select.ColumnString(1), "two");

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 4);
  ASSERT_EQ(select.ColumnString(1), "four");
  ASSERT_TRUE(db_.Execute("DELETE FROM rows WHERE id=2"));

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 6);
  ASSERT_EQ(select.ColumnString(1), "six");
  ASSERT_TRUE(db_.Execute("DELETE FROM rows WHERE id=4"));
  ASSERT_TRUE(db_.Execute("DELETE FROM rows WHERE id=6"));

  EXPECT_FALSE(select.Step());

  // Check that the DELETEs were applied as expected.

  static const char kSelectAllSql[] = "SELECT id,t FROM rows";
  sql::Statement select_all(
      db_.GetCachedStatement(SQL_FROM_HERE, kSelectAllSql));
  std::vector<int> remaining_ids;
  std::vector<std::string> remaining_texts;
  while (select_all.Step()) {
    remaining_ids.push_back(select_all.ColumnInt(0));
    remaining_texts.push_back(select_all.ColumnString(1));
  }

  std::vector<int> expected_remaining_ids = {3, 5};
  EXPECT_EQ(expected_remaining_ids, remaining_ids);
  std::vector<std::string> expected_remaining_texts = {"three", "five"};
  EXPECT_EQ(expected_remaining_texts, remaining_texts);
}

// The "No Isolation Between Operations On The Same Database Connection" section
// in https://sqlite.org/isolation.html states that it's safe to DELETE a row
// while a SELECT statement executes, but the DELETEd row may or may not show up
// in the SELECT results. (See the test above for a case where the DELETEd row
// is guaranteed to now show up in the SELECT results.)
//
// This seems to imply that DELETEing from a table that is not read by the
// concurrent SELECT statement is safe and well-defined, as the DELETEd row(s)
// cannot possibly show up in the SELECT results.
//
// Chrome features are allowed to rely on the implication above, because it
// comes in very handy for DELETEing data across multiple tables. This test
// ensures that our assumption remains valid.
TEST_F(SQLiteFeaturesTest, DeleteWhileSelectingFromDifferentTable) {
  ASSERT_TRUE(db_.Execute("CREATE TABLE main(id INTEGER PRIMARY KEY, t TEXT)"));
  ASSERT_TRUE(db_.Execute("INSERT INTO main VALUES(2, 'two')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO main VALUES(3, 'three')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO main VALUES(4, 'four')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO main VALUES(5, 'five')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO main VALUES(6, 'six')"));

  ASSERT_TRUE(
      db_.Execute("CREATE TABLE other(id INTEGER PRIMARY KEY, t TEXT)"));
  ASSERT_TRUE(db_.Execute("INSERT INTO other VALUES(1, 'one')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO other VALUES(2, 'two')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO other VALUES(3, 'three')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO other VALUES(4, 'four')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO other VALUES(5, 'five')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO other VALUES(6, 'six')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO other VALUES(7, 'seven')"));

  static const char kSelectEvenSql[] = "SELECT id,t FROM main WHERE id%2=0";
  sql::Statement select(db_.GetCachedStatement(SQL_FROM_HERE, kSelectEvenSql));

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 2);
  ASSERT_EQ(select.ColumnString(1), "two");
  EXPECT_TRUE(db_.Execute("DELETE FROM other WHERE id=2"));

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 4);
  ASSERT_EQ(select.ColumnString(1), "four");

  ASSERT_TRUE(select.Step());
  ASSERT_EQ(select.ColumnInt(0), 6);
  ASSERT_EQ(select.ColumnString(1), "six");
  ASSERT_TRUE(db_.Execute("DELETE FROM other WHERE id=4"));
  ASSERT_TRUE(db_.Execute("DELETE FROM other WHERE id=5"));
  ASSERT_TRUE(db_.Execute("DELETE FROM other WHERE id=6"));

  EXPECT_FALSE(select.Step());

  // Check that the DELETEs were applied as expected.

  static const char kSelectAllSql[] = "SELECT id,t FROM other";
  sql::Statement select_all(
      db_.GetCachedStatement(SQL_FROM_HERE, kSelectAllSql));
  std::vector<int> remaining_ids;
  std::vector<std::string> remaining_texts;
  while (select_all.Step()) {
    remaining_ids.push_back(select_all.ColumnInt(0));
    remaining_texts.push_back(select_all.ColumnString(1));
  }

  std::vector<int> expected_remaining_ids = {1, 3, 7};
  EXPECT_EQ(expected_remaining_ids, remaining_ids);
  std::vector<std::string> expected_remaining_texts = {"one", "three", "seven"};
  EXPECT_EQ(expected_remaining_texts, remaining_texts);
}

// The "No Isolation Between Operations On The Same Database Connection" section
// in https://sqlite.org/isolation.html states that it's possible to INSERT in
// a table while concurrently executing a SELECT statement reading from it, but
// it's undefined whether the row will show up in the SELECT statement's results
// or not.
//
// Given this ambiguity, Chrome code is not allowed to INSERT in the same table
// as a concurrent SELECT. However, it is allowed to INSERT in a table which is
// not covered by SELECT, because this greatly simplifes migrations. So, we test
// the ability to INSERT in a table while SELECTing from another table, to
// catch any regressions introduced by SQLite upgrades.
TEST_F(SQLiteFeaturesTest, InsertWhileSelectingFromDifferentTable) {
  ASSERT_TRUE(db_.Execute("CREATE TABLE src(id INTEGER PRIMARY KEY, t TEXT)"));
  ASSERT_TRUE(db_.Execute("CREATE TABLE dst(id INTEGER PRIMARY KEY, t TEXT)"));
  ASSERT_TRUE(db_.Execute("INSERT INTO src VALUES(2, 'two')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO src VALUES(3, 'three')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO src VALUES(4, 'four')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO src VALUES(5, 'five')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO src VALUES(6, 'six')"));

  static const char kSelectSrcEvenSql[] = "SELECT id,t FROM src WHERE id%2=0";
  sql::Statement select_src(
      db_.GetCachedStatement(SQL_FROM_HERE, kSelectSrcEvenSql));

  ASSERT_TRUE(select_src.Step());
  ASSERT_EQ(select_src.ColumnInt(0), 2);
  ASSERT_EQ(select_src.ColumnString(1), "two");
  EXPECT_TRUE(db_.Execute("INSERT INTO dst VALUES(2, 'two')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO dst VALUES(3, 'three')"));

  ASSERT_TRUE(select_src.Step());
  ASSERT_EQ(select_src.ColumnInt(0), 4);
  ASSERT_EQ(select_src.ColumnString(1), "four");
  ASSERT_TRUE(db_.Execute("INSERT INTO dst VALUES(4, 'four')"));

  ASSERT_TRUE(select_src.Step());
  ASSERT_EQ(select_src.ColumnInt(0), 6);
  ASSERT_EQ(select_src.ColumnString(1), "six");
  ASSERT_TRUE(db_.Execute("INSERT INTO dst VALUES(5, 'five')"));
  ASSERT_TRUE(db_.Execute("INSERT INTO dst VALUES(6, 'six')"));

  EXPECT_FALSE(select_src.Step());

  static const char kSelectDstSql[] = "SELECT id,t FROM dst";
  sql::Statement select_dst(
      db_.GetCachedStatement(SQL_FROM_HERE, kSelectDstSql));
  std::vector<int> dst_ids;
  std::vector<std::string> dst_texts;
  while (select_dst.Step()) {
    dst_ids.push_back(select_dst.ColumnInt(0));
    dst_texts.push_back(select_dst.ColumnString(1));
  }

  std::vector<int> expected_dst_ids = {2, 3, 4, 5, 6};
  EXPECT_EQ(expected_dst_ids, dst_ids);
  std::vector<std::string> expected_dst_texts = {"two", "three", "four", "five",
                                                 "six"};
  EXPECT_EQ(expected_dst_texts, dst_texts);
}

#if BUILDFLAG(IS_APPLE)
// If a database file is marked to be excluded from backups, verify that journal
// files are also excluded.
TEST_F(SQLiteFeaturesTest, TimeMachine) {
  ASSERT_TRUE(db_.Execute("CREATE TABLE t (id INTEGER PRIMARY KEY)"));
  db_.Close();

  base::FilePath journal_path = sql::Database::JournalPath(db_path_);
  ASSERT_TRUE(base::PathExists(db_path_));
  ASSERT_TRUE(base::PathExists(journal_path));

  // Not excluded to start.
  EXPECT_FALSE(base::mac::GetBackupExclusion(db_path_));
  EXPECT_FALSE(base::mac::GetBackupExclusion(journal_path));

  // Exclude the main database file.
  EXPECT_TRUE(base::mac::SetBackupExclusion(db_path_));

  EXPECT_TRUE(base::mac::GetBackupExclusion(db_path_));
  EXPECT_FALSE(base::mac::GetBackupExclusion(journal_path));

  EXPECT_TRUE(db_.Open(db_path_));
  ASSERT_TRUE(db_.Execute("INSERT INTO t VALUES (1)"));
  EXPECT_TRUE(base::mac::GetBackupExclusion(db_path_));
  EXPECT_TRUE(base::mac::GetBackupExclusion(journal_path));

  // TODO(shess): In WAL mode this will touch -wal and -shm files.  -shm files
  // could be always excluded.
}
#endif

#if !BUILDFLAG(IS_FUCHSIA)
// SQLite WAL mode defaults to checkpointing the WAL on close.  This would push
// additional work into Chromium shutdown.  Verify that SQLite supports a config
// option to not checkpoint on close.
TEST_F(SQLiteFeaturesTest, WALNoClose) {
  base::FilePath wal_path = sql::Database::WriteAheadLogPath(db_path_);

  // Turn on WAL mode, then verify that the mode changed (WAL is supported).
  ASSERT_TRUE(db_.Execute("PRAGMA journal_mode = WAL"));
  ASSERT_EQ("wal", ExecuteWithResult(&db_, "PRAGMA journal_mode"));

  // The WAL file is created lazily on first change.
  ASSERT_TRUE(db_.Execute("CREATE TABLE foo (a, b)"));

  // By default, the WAL is checkpointed then deleted on close.
  ASSERT_TRUE(base::PathExists(wal_path));
  db_.Close();
  ASSERT_FALSE(base::PathExists(wal_path));

  // Reopen and configure the database to not checkpoint WAL on close.
  ASSERT_TRUE(Reopen());
  ASSERT_TRUE(db_.Execute("PRAGMA journal_mode = WAL"));
  ASSERT_TRUE(db_.Execute("ALTER TABLE foo ADD COLUMN c"));
  ASSERT_EQ(
      SQLITE_OK,
      sqlite3_db_config(db_.db_, SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 1, nullptr));
  ASSERT_TRUE(base::PathExists(wal_path));
  db_.Close();
  ASSERT_TRUE(base::PathExists(wal_path));
}
#endif

}  // namespace sql


text:
<?php

final class FundInitiativeListController
  extends FundController {

  private $queryKey;

  public function shouldAllowPublic() {
    return true;
  }

  public function willProcessRequest(array $data) {
    $this->queryKey = idx($data, 'queryKey');
  }

  public function processRequest() {
    $controller = id(new PhabricatorApplicationSearchController())
      ->setQueryKey($this->queryKey)
      ->setSearchEngine(new FundInitiativeSearchEngine())
      ->setNavigation($this->buildSideNavView());

    return $this->delegateToController($controller);
  }

  public function buildSideNavView() {
    $user = $this->getRequest()->getUser();

    $nav = new AphrontSideNavFilterView();
    $nav->setBaseURI(new PhutilURI($this->getApplicationURI()));

    id(new FundInitiativeSearchEngine())
      ->setViewer($user)
      ->addNavigationItems($nav->getMenu());

    $nav->addLabel(pht('Backers'));
    $nav->addFilter('backers/', pht('Find Backers'));

    $nav->selectFilter(null);

    return $nav;
  }

  protected function buildApplicationCrumbs() {
    $crumbs = parent::buildApplicationCrumbs();

    $can_create = $this->hasApplicationCapability(
      FundCreateInitiativesCapability::CAPABILITY);

    $crumbs->addAction(
      id(new PHUIListItemView())
        ->setName(pht('Create Initiative'))
        ->setHref($this->getApplicationURI('create/'))
        ->setIcon('fa-plus-square')
        ->setDisabled(!$can_create)
        ->setWorkflow(!$can_create));

    return $crumbs;
  }

}


text:
class VVault_Encryption : public Encryption
{
public:

	VVault_Encryption(const unsigned long new_encKey = 0) : Encryption(new_encKey)
	{}
	~VVault_Encryption()
	{}

	//Public Functions
	void VVault_encrypt(string & dest, string & src);
	void VVault_decrypt(string & dest, string & src);
	void crc_set(BYTE & crc, const string & str);
	CODE_ERROR_T crc_check(const BYTE & crc, const string & str);
};

// Password Class ******************************************************************************************************

class VVault_Password : public Password
{
public:

	VVault_Password(const string & new_masterPswd) : Password(new_masterPswd)
	{}
	~VVault_Password()
	{}

	//Public Function
	bool VVault_Check_PasswordInput(const string & input);
};

#endif


text:
from __future__ import absolute_import
import os

if 'HEROKU' in os.environ:
    from .heroku import *
elif 'OPENSHIFT_HOMEDIR' in os.environ:
    from .openshift import *
elif 'NSA' in os.environ:
    from .nsa import *
else:
    from .dev import *

try:
    if SINGLE_PROCESS:
        # TODO: the next line is neccessery because celery-haystck needs to be fixed
        #       https://github.com/jezdez/celery-haystack/issues/21
        HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor'
        CELERY_ALWAYS_EAGER = True
except:
    ''' default is a multi process env '''
    from .multi import *


text:
use std::io;
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;

use pueue_lib::log::{get_log_file_handle, get_log_path, seek_to_last_lines};

/// Follow the log ouput of running task.
///
/// If no task is specified, this will check for the following cases:
///
/// - No running task: Print an error that there are no running tasks
/// - Single running task: Follow the output of that task
/// - Multiple running tasks: Print out the list of possible tasks to follow.
pub fn follow_local_task_logs(pueue_directory: &Path, task_id: usize, lines: Option<usize>) {
    let mut handle = match get_log_file_handle(task_id, pueue_directory) {
        Ok(stdout) => stdout,
        Err(err) => {
            println!("Failed to get log file handles: {err}");
            return;
        }
    };
    let path = get_log_path(task_id, pueue_directory);

    // Stdout handler to directly write log file output to io::stdout
    // without having to load anything into memory.
    let mut stdout = io::stdout();

    // If lines is passed as an option, seek the output file handle to the start of
    // the line corresponding to the `lines` number of lines from the end of the file.
    // The loop following this section will copy those lines to stdout
    if let Some(lines) = lines {
        if let Err(err) = seek_to_last_lines(&mut handle, lines) {
            println!("Error seeking to last lines from log: {err}");
        }
    }
    loop {
        // Check whether the file still exists. Exit if it doesn't.
        if !path.exists() {
            println!("File has gone away. Did somebody remove the task?");
            return;
        }
        // Read the next chunk of text from the last position.
        if let Err(err) = io::copy(&mut handle, &mut stdout) {
            println!("Error while reading file: {err}");
            return;
        };
        let timeout = Duration::from_millis(100);
        sleep(timeout);
    }
}


text:
using UnityEngine;
using System.Collections;

/// <summary>
/// Contains all tags used in a game project
/// useful for quick access to tags
/// @Author: Edgar Onukwugha
/// @Date: 11/02/13
/// </summary>
public class Tags : MonoBehaviour
{

    public const string player = "Player";
    public const string gameController = "GameController";
    public const string enemy = "Enemy";
    public const string collectable = "Collectable";
    public const string guiElement = "GUIElement";
    public const string projectile = "Projectile";
    public const string crystalShield = "CrystalShield";
    public const string crystal = "Crystal";
    public const string miniTurrret = "MiniTurret";
    public const string finishTimeText = "FinishedTimeText";
    public const string bestTimeText = "BestTimeText";
    public const string timesDisplay = "TimesDisplay";
}


text:
import bar, {version, api} from './bar';

(function (window, document, undefined) {
    'use strict';
    console.log('hello from the other side');

    const form = document.querySelector('.contact-form');

    function onSubmit (event) {
        event.preventDefault();
        console.log(event);
        const button = document.querySelector('#contact-form__button');
        const name = document.querySelector('input[name="name"]').value.replace(/[^A-z ]/g, '');
        const email = document.querySelector('input[name="email"]').value.toLowerCase();
        const subject = document.querySelector('input[name="subject"]').value.replace(/[^\w .+]/g, '');
        const body = document.querySelector('textarea[name="body"]').value.replace(/[^\w .+]/g, '');

        const message = { name:name, email:email, subject:subject, body:body };
        var messageKey = api.child('messages').push().key;

        button.disabled = true;

        api.child('/messages/' + messageKey + '/').set(message)
            .then(function () {
                alert('Message sent successfully.');
                form.reset();
            })
            .catch(function (error) {
                alert('Your message could not be sent at the moment.')
                console.warn(error);
            })
            .then(function () {
                button.disabled = false;
            });

        api.child('/user-messages/' + name.replace(/ /g, '').toLowerCase()
            + '/' + messageKey + '/').set(message);
    };

    form.addEventListener('submit', onSubmit);

} (window, document));

export default function foo() {
    console.log('foo');
    bar();
};


text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.resourcemanager.compute.models;

import com.azure.core.annotation.Fluent;
import com.azure.core.util.logging.ClientLogger;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

/** The VMScaleSetConvertToSinglePlacementGroupInput model. */
@Fluent
public final class VMScaleSetConvertToSinglePlacementGroupInput {
    @JsonIgnore
    private final ClientLogger logger = new ClientLogger(VMScaleSetConvertToSinglePlacementGroupInput.class);

    /*
     * Id of the placement group in which you want future virtual machine
     * instances to be placed. To query placement group Id, please use Virtual
     * Machine Scale Set VMs - Get API. If not provided, the platform will
     * choose one with maximum number of virtual machine instances.
     */
    @JsonProperty(value = "activePlacementGroupId")
    private String activePlacementGroupId;

    /**
     * Get the activePlacementGroupId property: Id of the placement group in which you want future virtual machine
     * instances to be placed. To query placement group Id, please use Virtual Machine Scale Set VMs - Get API. If not
     * provided, the platform will choose one with maximum number of virtual machine instances.
     *
     * @return the activePlacementGroupId value.
     */
    public String activePlacementGroupId() {
        return this.activePlacementGroupId;
    }

    /**
     * Set the activePlacementGroupId property: Id of the placement group in which you want future virtual machine
     * instances to be placed. To query placement group Id, please use Virtual Machine Scale Set VMs - Get API. If not
     * provided, the platform will choose one with maximum number of virtual machine instances.
     *
     * @param activePlacementGroupId the activePlacementGroupId value to set.
     * @return the VMScaleSetConvertToSinglePlacementGroupInput object itself.
     */
    public VMScaleSetConvertToSinglePlacementGroupInput withActivePlacementGroupId(String activePlacementGroupId) {
        this.activePlacementGroupId = activePlacementGroupId;
        return this;
    }

    /**
     * Validates the instance.
     *
     * @throws IllegalArgumentException thrown if the instance is not valid.
     */
    public void validate() {
    }
}


text:
  Saint-Vaast-en-Auge est
       un village
       localisé dans le département des Calvados en Basse-Normandie. On dénombrait 93 habitants en 2008.

Si vous envisagez de demenager à Saint-Vaast-en-Auge, vous pourrez facilement trouver une maison à acheter.

À coté de Saint-Vaast-en-Auge sont situées les communes de
Douville-en-Auge située à 3 km, 219 habitants,
Danestal à 4 km, 265 habitants,
Gonneville-sur-Mer à 2 km, 581 habitants,
Heuland à 2 km, 85 habitants,
Saint-Pierre-Azif située à 3 km, 141 habitants,
Grangues située à 4 km, 220 habitants,
 entre autres. De plus, Saint-Vaast-en-Auge est située à seulement 23 km de Le Havre.

Le parc d'habitations, à Saint-Vaast-en-Auge, se décomposait en 2011 en zero appartements et 69 maisons soit
 un marché relativement équilibré.