text:
\section{Introduction}

Let $S$ be a connected, orientable, finite-type surface. The \emph{curve complex} is the simplicial complex $\mathcal{C}(S)$  whose $k$-simplices are sets of to $k+1$ distinct isotopy classes of essential simple curves on $S$ that are pairwise disjoint.

The extended mapping class group, denoted $\mcg(S)$, acts naturally on the set of curves up to isotopy on $S$. This  action preserves  disjointness of curves, and therefore  extends to an action on the complex $\mathcal{C}(S)$. Via this action, the curve complex  works as a combinatorial model to study properties of $\mcg(S)$. For instance, a celebrated theorem of Ivanov in \cite{ivanov_automorphism_1997} asserts that for sufficiently complex surfaces the group $\mcg(S)$ is isomorphic to the group of simplicial automorphisms of the curve complex, a result  commonly known as \emph{simplicial rigidity.} In turn, this result is a key ingredient in establishing the isomorphism $\aut(\mcg(S))\cong \mcg(S)$.

The curve complex, and its applications to the mapping class group, has motivated the study of similar complexes associated to surfaces. For example, simplicial rigidity has been established for: the arc complex \cite{irmak_injective_2010}; the non-separating curve complex  \cite{irmak_complexes_2006}; the separating curve complex \cite{brendle_commensurations_2004}, \cite{kida_automorphisms_2011}; the Hatcher-Thurston complex \cite{irmak_automorphisms_2007}; and the pants graph \cite{margalit_automorphisms_2004} (see \cite{papadopoulos_simplicial_2012} for a survey on complexes associated to surfaces).

Another notion of rigidity which has been of recent interest is that of \emph{finite rigidity}: the simplicial complex $\mathcal{C}(S)$ is said to be finitely rigid if there exists a finite subcomplex $X$ such that any locally injective simplicial map \[\phi:X\to \mathcal{C}(S)\]is induced by a \emph{unique} mapping class, that is, there exists a unique  $h\in \mcg(S)$ such that the simplicial action $h:\mathcal{C}(S)\to \mathcal{C}(S)$ satisfies $h|_X = \phi$. Such $X$ is called a \emph{finite rigid set} of $\mathcal{C}(S)$ with \emph{trivial pointwise stabilizer}.

The finite rigidity of the curve complex was proven by Aramayona and Leininger in \cite{aramayona_finite_2013}, thus answering a question by Lars Louder. Furthermore, they constructed in \cite{aramayona_exhausting_2016} an exhaustion of $\mathcal{C}(S)$ by finite rigid sets with trivial pointwise stabilizers, thus recovering Ivanov's result \cite{ivanov_automorphism_1997} on the simplicial rigidity of $\mathcal{C}(S)$.

Following the result of Aramayona and Leininger,  finite rigidity has been proven for other complexes:  Shinkle proved it for the arc complex \cite{shinkle_finite_2020}   and the flip graph \cite{shinkle_finite_2022}; Hernández, Leininger and Maungchang proved a slightly different notion for the pants graph \cite{hernandezhernandez_finite_2021}; and Huang and Tshishiku proved a weaker notion for the separating curve complex \cite{huang_finite_2021}.

The main goal of this article is to prove the finite rigidity of the \emph{non-separating curve complex}, $\mathcal{N}(S)$, which is the subcomplex of $\mathcal{C}(S)$ spanned by the non-separating curves.  To prove the finite rigidity of $\mathcal{N}(S)$, the natural approach of restricting the finite rigid set of $\mathcal{C}(S)$ in \cite{aramayona_finite_2013} to $\mathcal{N}(S)$ does not work, as the restriction does not yield a finite rigid set in $\mathcal{N}(S)$. Below, we construct a different subcomplex of $\mathcal{N}(S)$ and prove its rigidity.

Our main result is compiled in the next theorem.

\begin{theorem}\label{thm:fr}
  Let $S$  be a connected, orientable, finite-type surface of genus $g\geq 3$. There exists a finite simplicial complex $X\subset \mathcal{N}(S)$ such that any locally injective simplicial map \[\phi:X \to \mathcal{N}(S)\] is induced by a unique  $h\in \mcg(S)$.
\end{theorem}

Our second result produces an exhaustion of the non-separating curve complex by finite rigid sets:

\begin{theorem}\label{thm:exh}
  Let $S$  be an orientable finite type surface of genus $g\geq 3$. There exist subcomplexes $X_1\subset X_2 \subset \dots \subset \mathcal{N}(S)$ such that \[\bigcup_{i=1}^\infty X_i = \mathcal{N}(S)\] and each $X_i$ is a finite rigid  set with trivial pointwise stabilizer.
\end{theorem}

From Theorem \ref{thm:exh} we can recover the simplicial rigidity of $\mathcal{N}(S)$ (see \cite[Theorem 1.1]{irmak_edge-preserving_2020}):

\begin{corollary}
  Let $S$ be a connected, orientable, finite-type surface of genus $g\geq 3$. Any locally injective simplicial map $\phi: \mathcal{N}(S)\to \mathcal{N}(S)$ is induced by a unique $h\in \mcg(S)$. In particular, this yields an isomorphism between $\mcg(S)$ and  the group of simplicial automorphisms of $\mathcal{N}(S)$.
\end{corollary}

\subsection*{Plan of the paper} In Section \ref{sec:preliminaries} we introduce some basic definitions that will be required. In Section \ref{sec:frs} we introduce the notion of finite rigid sets. Sections \ref{sec:fr_no_puncs} and \ref{sec:exh_no_puncs} deal with the proofs of Theorems \ref{thm:fr} and \ref{thm:exh} for closed surfaces. Lastly, sections \ref{sec:fr_puncs} and \ref{sec:exh_puncs} presents the proofs of theorems \ref{thm:fr} and \ref{thm:exh} for punctured surfaces.

\subsection*{Acknowledgements}
The author would like to thank his supervisor Javier Aramayona for suggesting the problem and for the guidance provided.

The author acknowledges financial support from grant CEX2019-000904-S funded by MCIN/AEI/ 10.13039/501100011033.

\section{Preliminaries}\label{sec:preliminaries}

  Let $S$ be connected, orientable surface without boundary. We will further assume that $S$ has finite type, i.e, $\pi_1(S)$ is finitely generated. As such, $S$ is homeomorphic to $S_{g,n}$, the result of removing $n$ points from a genus $g$ surface. We refer to the removed points as \emph{punctures}. If $S$ has no punctures, we will say $S$ is \emph{closed}. Otherwise, we will refer to $S$ as a \emph{punctured} surface.

  Before fervently jumping into the proofs, we warn the reader that the classification of surfaces, the change of coordinates principle and the Alexander method will be frequently used in proofs, sometimes without mention. For these and other fundamental results on mapping class groups, we refer the reader to  \cite{farb_primer_2012}.

  \subsection{Curves}
  By a curve $c$ in $S$ we will mean the isotopy class of a simple closed curve that does not bound a disk or a punctured disk. Throughout the article, we will  make no distinction  between  curves and their  representatives. We will say $c$ is \emph{non separating} if there is a representative  $\gamma$  of $c$ such that the surface that results from cutting $S$ along $\gamma$, denoted $S\setminus \gamma$, is connected.

  The \emph{intersection number} $i(a,b)$  between two curves $a$ and $b$ is the minimum intersection number between representatives of $a$ and $b$. If $i(a,b)=0$, we will say the curves $a$ and $b$ are \emph{disjoint}.

  Given a set of curves $\{c_1,\dots, c_k\}$, we will denote the set of boundary components of a regular neighborhood of  $\bigcup c_i$ by
  \[\partial(c_1, \dots, c_k).\]

  \subsection{Non-separating curve complex}
  The \emph{non-separating curve complex}  $\mathcal{N}(S)$ is the  simplicial complex whose  $k$-simplices are sets of $k+1$ isotopy classes of pairwise disjoint curves.

  Note that we can endow $\mathcal{N}(S)$ with a metric by declaring each $k$-simplex to have the standard euclidean metric and considering the resulting path metric on $\mathcal{N}(S)$.

  \subsubsection{Pants decompositions}

  The dimension of $\mathcal{N}(S_{g,n})$ is $3g-3+n$ and the vertex set of a top dimensional simplex in  $\mathcal{N}(S_{g,n})$ is called a \emph{pants decomposition} of $S_{g,n}$. If $P=\{c_1,\dots, c_k\}$ is a pants decomposition of $S$, then $S\setminus \bigcup c_i$  is a union of  \emph{pairs of pants} (i.e, a union of subsurfaces homeomorphic to $S_{0,3}$).

  Let $P=\{c_1,\dots, c_k\}$ be a pants decomposition of the surface $S$. Two curves $c_i,c_j \in P$ are said to be \emph{adjacent rel to P} if there exist a curve $c_k \in P$ such that $c_i, c_j, c_k$ bound a pair of pants in $S$; see Figure \ref{fig:pant_decomp_nopuncs}  for an example.

  We record the following observation for future use.
  \begin{remark}\label{rmk:at_least_adj_curves}
    Let $P$ be a pants decomposition of $S_{g,n}$, where $g\geq 3$:

    \begin{itemize}
    \item  If $n\leq 1$, then every curve in $P$ is adjacent rel to $P$ to at least three other curves.
    \item If $n>1$, then every curve is adjacent to at least two other curves.
  \end{itemize}

  \end{remark}

  Consider $A \subset P$, where $P$ is a pants decomposition of  $S$. We say that a set of curves $\tilde{A}$ \emph{substitutes $A$ in $P$} if \[ (\tilde{A} \cup P) \setminus A \]  is a pants decomposition. In words, we say $\tilde{A}$ substitutes $A$ in $P$ if both sets have no curves in common and we can replace the curves in $A$ by the curves in $\tilde{A}$ and still get a pants decomposition.

  \section{Finite rigid sets}\label{sec:frs}

  For a simplicial subcomplex $X \subset \mathcal{N}(S)$, a map $\phi: X \to \mathcal{N}(S)$ is  said to be a \emph{locally injective simplicial map}  if $\phi$ is  simplicial and injective on the star of each vertex.

  As mentioned in the introduction, the main goal of this article is to construct a finite subcomplex $X\subset \mathcal{N}(S)$ with the following properties:

  \begin{definition}[Finite rigid set]
    A \emph{finite rigid set} $X$ of $\mathcal{N}(S)$ is a finite subcomplex such that any locally injective simplicial  map $\phi: X \to \mathcal{N}(S)$ is induced by a mapping class, i.e, there exists $h\in \mcg(S)$ with $h|_X = \phi$.

    In addition, if $h$ is unique, we say $X$ has \emph{trivial pointwise stabilizer}.
  \end{definition}

  Observe that a subcomplex $X\subset \mathcal{N}(S)$ has trivial pointwise stabilizer if and only if the inclusion $X \hookrightarrow \mathcal{N}(S)$ is induced uniquely by the identity $1\in \mcg(S)$, hence the name.

  \begin{remark}
    By the change of coordinates principle (see \cite[Chapter 1.3]{farb_primer_2012}), every vertex $\{v\} \subset \mathcal{N}(S)$ is a finite rigid set. However, the stabilizer of $\{v\}$ is not trivial.
  \end{remark}
  \begin{remark}
    If $X$ is a finite rigid set and $X\subset Y$, then $Y$ may not be a finite rigid set. For example:

    Consider two disjoint curves $v_1,v_2$ such that $S\setminus \bigcup v_i$ is connected, and two disjoint curves $v_1',v_2'$ such that $S\setminus \bigcup v_i'$ is disconnected. Now, take $X=\{v_1\}$, $Y=\{v_1,v_2\}$ and the locally injective simplicial  map $\phi(v_i)=v_i'$. Clearly, $\phi$ is not induced by a mapping class and so $Y$ is not a finite rigid set of $\mathcal{N}(S)$. Note that $X$ is a finite rigid set of $\mathcal{N}(S)$ by the remark above.
  \end{remark}

  Following Aramayona and Leininger in \cite{aramayona_finite_2013}, we will say that a subcomplex $X\subset \mathcal{N}(S)$  \emph{detects the intersection} of two curves $a,b \in X$, if every locally injective simplicial  map $\phi: X \to \mathcal{N}(S)$ satisfies
\[i(a,b)\neq 0 \Leftrightarrow  i(\phi(a),\phi(b)) \neq 0.\]

\section{Finite rigid sets for closed surfaces}\label{sec:fr_no_puncs}
In this section we construct  finite rigid sets for closed surfaces and prove their rigidity. This will establish  Theorem \ref{thm:fr} for closed surfaces.

\subsection{Constructing the finite rigid set}

Let $S$ be a closed surface of genus $g\geq 3$. Consider the following curves:
\begin{itemize}
  \item The pants decomposition $P$ formed by the curves $\{p_1,\dots, p_{g+1}\}$,  $\{ p_2^-, \dots, p_{g-1}^-\}$ and $\{p_2^+,\, \dots,\, p_{g-1}^+ \}$  as in Figure \ref{fig:pant_decomp_nopuncs}.
  \item The `circular' curves $C = \{ c_1, \dots, c_g, c_{g+1}\}$ as in Figure \ref{fig:circular_nopuncs}.
  \item The `up' curves $U=\{u_k \mid k\in\{2,\dots, g-1\}\}$ and the `down' curves $D = \{d_k\mid k\in\{2,\dots, g-1\}\}$ as in Figure \ref{fig:ctilde}.
  \item The `left' curves  $L = \{l_2, \dots, l_{g-2}\}$, where  $l_k$ is the unique curve of $\partial(p_k,c_k, p_k^+ )$ that is not an element of $P$. Analogously, let  $R=\{r_2, \dots, r_{g-2}\}$ be the set of `right' curves, where $r_k$ is the unique curve in  $\partial( {p_{k+1}}^+, c_{k+1}, p_{k+2})$ that is not in $P$. For examples of a left and a right curves see Figure  \ref{fig:upper}.
  \item Lastly, the `non symmetrical' left, right and down curves  $N:=\{nl,nr,nd\}$ in Figures \ref{fig:el_er} and \ref{fig:ed}. These are called non symmetrical since they are not preserved by the back-front orientation reversing involution of $S$.
\end{itemize}

\begin{figure}[h]
  \centering
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/pants.JPEG}
  \caption{Pants decomposition $P$ of surface $S_g$. As an example, note that $p_1$ and $p_2$ are adjacent rel to $P$; while $p_1$ and $p_3$ are not adjacent rel to $P$.}
  \label{fig:pant_decomp_nopuncs}
  \end{subfigure}
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/C.JPEG}
  \caption{Circular curves $C$.}
  \label{fig:circular_nopuncs}
  \end{subfigure}\par\medskip

  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/ud.JPEG}
  \caption{Up and down curves $u_k, d_k$.}
  \label{fig:ctilde}
  \end{subfigure}
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/lr.JPEG}
  \caption{Left and right curve $l_k, r_k$.}
  \label{fig:upper}
  \end{subfigure}\par\medskip

  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/nl.JPEG}
  \caption{Non symmetrical left and right curves $nl, \, nr$.}
  \label{fig:el_er}
  \end{subfigure}
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/nd.JPEG}
  \caption{Non symmetrical down curve $nd$.}
  \label{fig:ed}
  \end{subfigure}
  \caption{Curves in $F_R$ for a closed surface.}
\end{figure}

We set $F_R$ to be the   subcomplex of $\mathcal{N}(S)$  spanned by
\[ P \cup C \cup U \cup D \cup L \cup R \cup N.\]

\begin{remark}\label{rmk:dist_two}
  Note that the subcomplex  $F_R$   has diameter two. Thus, any locally injective simplicial  map $\phi: F_R \to \mathcal{N}(S)$ is injective.
\end{remark}

\subsection{Proving the rigidity of $F_R$} The first step is to check that the locally injective simplicial  map $\phi: F_R \to \mathcal{N}(S)$ preserves the \emph{non} adjacency rel to $P$. To do so, we require the following technical lemma:

\begin{lemma}\label{lemma:non_adj}
  Let $S$ be a finite-type surface,  $F_R \subset \mathcal{N}(S)$ a  subcomplex, $P\subset F_R$ a pants decomposition and $a,b\in P$ two  curves. If there exist subsets $A,B \subset P$ and $\tilde{A}, \tilde{B} \subset F_R$ satisfying the following:
  \begin{itemize}
    \item $a\in A$ and $b\in B$,
    \item $\tilde{A}$ substitutes $A$ in $P$,
    \item $\tilde{B}$ substitutes $B$ in $P$,
    \item $\tilde{A} \cup \tilde{B}$ substitutes $A\cup B$ in $P$, and
    \item $A\cap B=\emptyset$.
  \end{itemize}
  Then $a,b$ are not adjacent rel to $P$.
\end{lemma}
\begin{proof}
  We will proceed by contradiction. Suppose the curves  $a,b$ are adjacent in a pair of pants $Q$ bound by $a,b,c$. Since $A\cap B =\emptyset$ either $c\not \in A$ or $c\not \in B$. Without loss of generality, suppose $c\not \in A$.

  If $\tilde{A}$ is a substitution of $A$ and  $A \cap B = \emptyset$, then there is a curve $\tilde{a}\in \tilde{A}$ such that $i(\tilde{a},  a)\neq 0$, $i(\tilde{a}, b)=0$ and $i(\tilde{a}, c) = 0$. Now, note that since $\tilde{A}\cup \tilde{B}$ is a substitution, there exists  $\tilde{b}\in \tilde{B}$ with $i (\tilde{b}, b )\neq 0$ and $i(\tilde{b} , \tilde{a}) = 0$. However, is impossible to have arcs  $\tilde{a}\cap Q$ and $\tilde{b}\cap Q$ satisfying the intersections above (see Figure \ref{fig:arcsQ}).
\end{proof}
\begin{figure}
  \begin{center}
  \includegraphics[width=0.30\linewidth]{img/arcos.jpeg}
  \caption{ There can be no arc $\tilde{b}\cap Q$ that intersects $b$ and  does not intersect $\tilde{a}\cup a$.}
  \label{fig:arcsQ}
  \end{center}
\end{figure}

Now, we prove that $\phi$ preserves non adjacency rel to $P$:

\begin{lemma}\label{lemma:compact_non_adj_rel_p}
  Let $S$ be a  closed surface of genus $g\geq 3$ and  $\phi: F_R \to \mathcal{N}(S)$ a locally injective simplicial  map. If $a,b\in P$ are not adjacent rel to $P$, then $\phi(a),\phi(b)$ are not adjacent rel to $\phi(P)$
\end{lemma}
\begin{proof}
  Consider two curves $a,b \in P$ such that there exists $A,B \subset P$ and $\tilde{A},\tilde{B}\subset F_R$ as in Lemma \ref{lemma:non_adj}. Under these conditions, the lemma ensures that $a$ and $b$ are non adjacent rel to $P$. Moreover, these properties are preserved by $\phi$, so in that case we know $\phi(a)$ and $\phi(b)$ are not adjacent rel to $\phi(P)$.

  By means of the method above, we are only left to find appropriate subsets $A, \tilde{A}, B ,\tilde{B}$  for any non-adjacent curves $a,b\in P$. We will find such subsets for certain $a, b\in P$, as the rest of the cases are similar.

  If $a=p_k$ and $b=p_{k+1}$ for $k\in\{3,\dots, g-3\}$. We can consider $A=\{p_{k-1}^-,p_k\}$ and $\tilde{A}=\{l_{k-1}, d_{k-1}\}$, $B=\{p_{k+1}, p_{k+1}^-\}$ and $\tilde{B}=\{r_k, d_{k+1}\}$. It is straightforward to check that these subsets satisfy conditions of Lemma \ref{lemma:non_adj} and so $\phi(a)$ is not adjacent rel to $P$ to $\phi(b)$.

  If $a=p_1$. Consider $A = \{p_1,p_2\}$ and $\tilde{A}=\{nl, c_1\}$, then
  \begin{itemize}
    \item If $b\in \{p_g, p_{g+1}\}$,  take $B = \{p_g,p_{g+1}\}$ and $\tilde{B} = \{nr,c_g\}$.
    \item If $b \in \{p_k, {p_k^-}\}$ for $k\in \{3, \dots, g-1\}$, consider $B= \{p_k, {p_k^-}\}$ and $\tilde{B} = \{{c^-_k},r_{k-1}\}$.
    \item If $b=p_k^+$ for $k\in \{3, \dots, g-1\}$, consider $B = \{{p_k^+}\}$ and $\tilde{B}=\{u_k\}$.
  \end{itemize}

\end{proof}

\begin{remark}
  The curves $L\cup R\subset F_R$ are exclusively used to determine the non adjacency rel to $P$ in the above lemma.
\end{remark}

Using the previous result, we now prove that $\phi$  preserves adjacency rel to $P$:

\begin{lemma}\label{lemma:compact_adj_rel_p}
  Let $S$ be a  closed surface of genus $g\geq 3$ and   $\phi: F_R \to \mathcal{N}(S)$  a locally injective simplicial  map. If $a,b \in P$ are adjacent rel to $P$, then $\phi(a),\phi(b)$ are adjacent rel to $\phi(P)$.
\end{lemma}
\begin{proof}
  Take $\phi(p_1) \in \phi(P)$. From the non adjacency rel to $\phi(P)$, it follows that $\phi(p_1)$ has at most three adjacent curves. On the other hand,  Remark \ref{rmk:at_least_adj_curves} implies that  $\phi(p_1)$ has at least three adjacent curves. Thus, we conclude that $\phi(p_1)$ has exactly three adjacent curves, namely $\phi(p_2), \phi(p_2^+), \phi(p_2^-)$. Naturally, the same argument applies to $\phi(p_2)$.

  We now determine the curves adjacent to $\phi(p_2^+)$ and $\phi(p_2^-)$. First, note that the adjacency rel to $P$ of $\phi(p_1)$ and $\phi(p_2)$ implies that  $\phi(p_2^+)$ and $\phi(p_2^-)$ bound a subsurface homeomorphic to $S_{1,2}$. Since both curves $\phi(p_2^+)$ and $\phi(p_2^-)$ are non separating, it follows that both have  four adjacent curves rel to $P$. Finally, considering the non adjacency rel to $P$, and by a process of elimination, we have that $\phi(p_2^+)$ is adjacent to  \[\{\phi(p_1), \phi(p_2), \phi(p_3), \phi(p_3^+)\}\] and $\phi(p_2^-)$ is adjacent to  \[ \{\phi(p_1), \phi(p_2), \phi(p_3), \phi(p_3^-)\}.\]

  In the same fashion, we can argue inductively to determine the adjacency of each curve in $\phi(P)$.
\end{proof}

As a corollary we obtain that $\phi$ preserves the topological type of $P$:

\begin{corollary}\label{lemma:fr_top_typ}
  Let $S$ be a  finite-type surface and   $\phi: F_R \to \mathcal{N}(S)$  a map that preserves adjacency rel to $P$. There exists $h\in \mcg(S)$ such that $h|_P=\phi|_P$.
\end{corollary}
\begin{proof}
  We construct a homeomorphism $h$ inductively by gluing abstract pairs of pants.

  Consider the pairs of pants $Q_1, \dots, Q_k \subset S$ bound by curves in $P$ and denote $Q'_1, \dots,Q'_k \subset S$ the pairs of pants such that $\partial Q'_i = \phi(\partial Q_i)$. Any two pairs of pants are homeomorphic, thus we can consider homeomorphisms $h_i(Q_i)=Q'_i$. Since $\phi$ preserves the adjacency rel to $P$, we can ensure these homeomorphisms agree on the boundary curves. Then, by gluing the maps $h_i$ we obtain a homeomorphism $h$ of the surface such that $h|_P=\phi|_P$.
\end{proof}

 Using Lemma \ref{lemma:compact_adj_rel_p} and Corollary \ref{lemma:fr_top_typ}, we have constructed a homeomorphism of the surface that coincides with $\phi$ on $P\subset F_R$. To complete the proof of Theorem \ref{thm:fr} in the closed case, we must show that the homeomorphism can be taken to agree with $\phi$ on the rest of the curves of $F_R$. Next, we proceed to do so for certain curves.

\begin{lemma}\label{lemma:aaa}
  Let $S$ be a  closed surface of genus $g\geq 3$ and   $\phi: F_R \to \mathcal{N}(S)$ a locally injective simplicial  map. There exists $h\in \mcg(S)$ such that $h|_{F_R\setminus N}=\phi|_{F_R\setminus N}$.
\end{lemma}
\begin{remark}
  In the following proof the reader should keep in mind the image of the surface with the fixed pants decomposition $P$ (see Figure \ref{fig:pant_decomp_nopuncs}) and try to see the intersections pictorially.
\end{remark}
\begin{proof}
  By Corollary \ref{lemma:fr_top_typ} there exists $h\in \mcg(S)$ such that $h\circ \phi$ fixes the pants decomposition $P$; we rename $h\circ \phi$ to $\phi$. Recall that by Remark $\ref{rmk:dist_two}$ we know $\phi$ is injective.

  First, we prove that $F_R$ detects the following intersections
  \begin{enumerate}
    \item $u_k$ with $p_k^+$, for $k\in\{2,\dots,g-1\}$.\label{lem:1}
    \item $d_k$ with $p_k^-$, for $k\in \{2,\dots, g-1\}$.\label{lem:2}
    \item $c_k$ with curves in $P$, for $k\in \{2,\dots, g-1\}$. \label{lem:3}
    \item $c_{k}$ with curves in $P$, for $k\in \{1, g, g+1\}$. \label{lem:4}
  \end{enumerate}

  To prove (\ref{lem:1}), observe that $ \{\phi(u_k)\} \cup P\setminus\{p_k^+\}$ is a pants decomposition. Therefore, $i(p_k^+, \phi(u_k))=0$ would lead to a contradiction with the dimension of $\mathcal{N}(S)$. The same applies to (\ref{lem:2}).

  To prove (\ref{lem:3}), we need to check that $\phi(c_k)$ intersects the curves $p_k, p_{k+1}, p_k^+$ and $p_k^-$. First, consider  the pants decomposition \[P' := \{\phi(u_k), \phi(d_k)\} \cup  P\setminus\{p_k^+, p_k^-\}.\] Taking into account the disjointness of $\phi(c_k)$ with $P' \setminus\{p_k,p_{k+1}\}$, it follows that $\phi(c_k)$ intersects  $p_k$ or $p_{k+1}$. Without loss of generality, assume $\phi(c_k)$ intersects $p_k$. By disjointness of $\phi(c_k)$ with $\phi(u_k)$ and  $\phi(d_k)$, we have that $\phi(c_k)$ intersects both $p_k^+$ and $p_k^-$. Clearly, the same argument holds to deduce that $\phi(c_{k+1})$ intersects $p_{k+1}^+$ and  $p_{k+1}^-$. Now, if $i(\phi(c_k), p_{k+1})=0$, then $\phi(c_k)$ and $\phi(c_{k+1})$ would  intersect, leading to a contradiction, thus $i(\phi(c_k), p_{k+1})\neq 0$.

  To prove (\ref{lem:4}) for $k=g+1$ we need to check that $\phi(c_{g+1})$ intersects every curve in $\{p_1,p_{g+1}\} \cup \{{p_j^-}, {p_i^+}| \: \forall i,j\}$. If $\phi(c_{g+1})$ was disjoint from any curve in $\{p_1,p_{g+1}\} \cup \{{p_j^-}, {p_i^+}| \: \forall i,j\}$, then a contradiction would arise  by disjointness with one of the curves  $\phi(u_k), \phi(d_k), \phi(c_1),\phi(c_2),\phi(c_{g-1})$ or  $\phi(c_{g})$.

  Lastly, that the intersections of $\{\phi(c_1),\phi(c_{g})\}$ with $P$ are detected follows easily from the previous ones with similar arguments.

  Note that the argument above not only detects the intersections between curves, but also yields arcs between intersection points (up to homotopy). For instance,  consider the subsurface $S'=S_{0,4}$  bound by the curves \[p_{k-1}^+, p_{k}, p_{k+1}, p_{k+1}^+;\] the argument indicates not only that $\phi(c_k)$ intersects both $p_k, p_{k+1}$, but also  that there is an arc of $S' \cap \phi(c_k)$ connecting the boundaries $p_k$ and $p_{k+1}$.

  Next, we proceed to characterize  curves in $\phi(F_R\setminus N)$.

  Consider $c_1\in C$. First, note that by the intersections of $\phi(c_1)$ with curves in $P$, we can deduce that $\phi(c_1)$ is contained the subsurface $S'=S_{1,2}\subset S$ bound by $p_2^+$ and $p_2^-$. Moreover, $\phi(c_1)$ is  disjoint from the arcs $a_1=\phi(c_{2})\cap S'$ and $a_2=\phi(c_{g+1})\cap S'$. Since $S'\setminus \bigcup a_i$ is an annulus, we have that $\phi(c_1)$ is the only curve contained in that annulus. Notice that by Dehn twisting along $p_1,p_2, p_2^-$  and $p_2^+$ we can construct $h'\in \mcg(S)$ such that $h'\circ \phi (c_1)=c_1$; we rename $h'\circ \phi$ to $\phi$. Using analogous arguments we can inductively construct $h''\in \mcg(S)$ such that $h''\circ \phi(c)=c$ for every $c\in\{c_1,\dots, c_g\}$; we rename $h''\circ \phi$ to $\phi$.

  To finish the proof, we are going to see that now $\phi$  fixes curves in $\{c_{g+1}\} \cup U \cup D \cup L\cup R  $.

  To see that $\phi$ fixes $c_{g+1}$, notice that $\phi(c_{g+1})$ is disjoint from the curves $p_2, \dots, p_g, c_1, \dots, c_g$. The complementary of the union of these curves is an annulus, which implies that $\phi(c_{g+1})=c_{g+1}$.

  In a similar way, we can use the intersections to deduce that $\phi(u_k)$ is contained in the subsurface $S'=S_{0,4}$ bound by $p_{k-1}^+, p_k, p_{k+1}$ and  $p_{k+1}^+$. Since $\phi(u_k)$ is disjoint from the arc $a = S'\cap c_{g+1}$, we have that $\phi(u_k)$ is the only curve contained in the annulus $S' \setminus a$, implying $\phi(u_k)=u_k$. The same argument changing $p_{k-1}^+, p_{k+1}^+$ to $p_{k-1}^-, p_{k+1}^-$ proves that $\phi(d_k)=d_k$.

  Finally,  the intersections above imply that $\phi(l_k)$ is contained in  the subsurface $S'=S_{0,5}$  bound by $p_{k-1}^-,p_k, p_k^+, p_{k+1}^-$ and $p_{k+1}^+$. Since $\phi(l_k)$ is disjoint from $a_1 = c_k\cap S'$ and $a_2 = c_{k+1}\cap S'$, we have that $\phi(l_k)$ is contained in to the pair of pants $S'\setminus \bigcup a_i$. Notice that one of the boundaries of the pair of pants is a separating curve and another one is $p_{k-1}^-$. Thus, by injectivity of $\phi$, it follows that $\phi(l_k)$ is the remaining boundary of the pair of pants, i.e, $\phi(l_k)=l_k$. The same argument with slight modifications yields that $\phi(r_k)= r_k$.

  Summarizing, we have proven that there exists a mapping class $f\in \mcg(S)$ such that $f\circ \phi$ fixes $F_R\setminus N$. In other words, $f^{-1}|_{F_R\setminus N} = \phi|_{F_R\setminus N}$.
\end{proof}

 Now, to finish the proof of Theorem \ref{thm:fr} in the closed case, we are only left to characterize the curves ${nl,nr,nd}$ and prove the uniqueness of the inducing mapping class.

\begin{proof}[Proof of Theorem \ref{thm:fr}  for closed surfaces]
  Let $\phi: F_R \to \mathcal{N}(S)$ be a locally injective simplicial  map. By Lemma \ref{lemma:aaa} there exists $h\in \mcg(S)$ such that $h \circ \phi$ fixes $F_R\setminus N$, we rename $h\circ \phi$ as $\phi$. Now, let us characterize curves in $N$. To this end, consider the set of curves \[ \Lambda :=\{p_3,c_3,p_4,\dots, p_{g-1},c_{g-1}\} \cup \{c_2, p_2^+, {p_{g-1}^+}, c_1, c_g, c_{g+1}\}\] all fixed by $\phi$. Note that $\phi(nd)$ is disjoint from all the curves in $\phi( \Lambda)= \Lambda$. Even more, $\phi(nd)$ is contained in one of the two pairs of pants of $S'=S\setminus \bigcup_{a\in  \Lambda} a$ . In each pair of pants, there is only one boundary that is not already a curve in $F_R\setminus N$. Using the injectivity of $\phi$, it follows that $\phi(nd)$ is one of those boundary components, i.e, it is either $nd$ or $\iota(nd)$, where $\iota$ is the back-front orientation reversing involution of $S$.

  Notice that we can now assume $\phi$ fixes $nd$ by precomposing with $\iota$ if necessary. Now, using that $\phi$ fixes $P\cup C$, observe that $\phi(nl)$ is contained in  a subsurface $S'=S_{0,4}$ bound by $p_2^+, p_2^-, c_1$. Furthermore, $\phi(nl)$ is disjoint from the arc $a= S'\cap nd$, thus $\phi(nl)$ is the only curve in the annulus $S'\setminus a$, that is, $\phi(nl)=nl$. Simple modifications in the argument yield $\phi(nr)=nr$.

  So far, we  have found a composition of mapping classes $f\in \mcg(S)$ such that $f \circ \phi$ is the identity in $F_R$. Therefore, $\phi$ is induced by the mapping class $f^{-1}$.

  To prove the uniqueness of the inducing mapping class, suppose $f,\tilde{f}\in \mcg(S)$ both induce the same $\phi: F_R\to \mathcal{N}(S)$. Since $g = \tilde{f}\circ f^{-1}$ fixes the curves \[\{p_1, c_1, \dots, p_g, c_g\} \cup \{p_2^-\}\subset F_R,\]
  the Alexander method implies that $g$ is either the identity or the back-front orientation reversing involution of $S$. However, since $g$ also fixes the curve $nd$, then $g$ is the identity and  $f=\tilde{f}$.
\end{proof}

\section{Finite rigid exhaustion for closed surfaces}\label{sec:exh_no_puncs}

In this section we prove that for a closed surface $S$ of genus $g\geq 3$, there exist subcomplexes $F_{1} \subset F_{2} \subset  \dots \subset \mathcal{N}(S)$ such that each $F_{i}$ is a finite rigid set with trivial pointwise stabilizer and \[\bigcup_{i=1}^\infty F_{i} = \mathcal{N}(S).\]

The strategy to produce an  exhaustion is to first extend  $F_R$ to a larger finite rigid set $F_{1}$ with desirable properties. Then, the set $F_{1}$ will work as base case for an induction  that  enlarges $F_{i}$ into $F_{i+1}$. This method heavily resembles the proof given by Aramayona and Leininger in \cite{aramayona_exhausting_2016} to produce an exhaustion of the curve complex.

The plan of the proof is summarized in the following lemma (cf. \cite[Lemma 3.13]{aramayona_exhausting_2016}):

\begin{lemma}\label{lemma:create_exh}
  Let $S$ be a finite-type surface and let $F_{1} \subset \mathcal{N}(S)$ be a a finite rigid set with trivial pointwise stabilizer and $\{h_1, \dots, h_k\}$ a set of generators of $\mcg(S)$. If $F_{1}\cup h_j(F_{1})$ is a  finite rigid set with trivial pointwise stabilizer for every $j$, then the sets   \[
     F_{i+1} = F_{i} \cup \bigcup_{j=1}^k \left( h_j(F_{i}) \cup  h_j^{-1}(F_{i}) \right),
  \]
  satisfy that $F_{1} \subset F_{2} \subset \dots \subset \mathcal{N}(S)$, $\bigcup F_i  = \mathcal{N}(S)$ and every $F_{i}$ is finite rigid with trivial pointwise stabilizer.
\end{lemma}
\begin{proof}
  First, notice that if $F_{1}\cup h_j(F_{1})$ is a finite rigid set with trivial stabilizer, then the same holds for $F_{1}\cup h_j^{-1}(F_{1})$.

  We will now check that $F_{2}$ is finite rigid with trivial stabilizer: take $\phi: F_{2} \to \mathcal{N}(S)$ and observe that by hypothesis there exists $f_j \in \mcg(S)$ such that \[\phi|_{F_{1}\cup h_j(F_{1})} = f_j|_{F_{1}\cup h_j(F_{1}),} \]for every $j\in \{1,\dots,k\}$. Since $F_{1}$ has trivial pointwise stabilizer and \[f_j |_{F_{1}} = \phi|_{F_{1}}=  f_k |_{F_{1}},\] we deduce  $f_j = f_k$ for all $j,k$. Clearly, the same argument holds when considering $F_{1} \cup h_j^{-1}(F_{1})$. It follows that $\phi = f$ for $f\in \mcg(S)$ and  $F_{2}$ is a finite rigid set with trivial pointwise stabilizer.

  For $F_{i+1}$ we proceed by induction. Consider $\phi: F_{i+1}\to \mathcal{N}(S)$, by induction we have $\phi|_{F_{i}} = f|_{F_{i}}\in \mcg(S)$ and \[\phi|_{h_j(F_{i})} = f_j|_{h_j(F_{i})}\] for some $f_j\in \mcg(S)$. Observe that $F_{1} \subset F_{i} \cap h_j(F_{i})$ and $F_{1}$ is trivially stabilized, thus $f=f_j$ for every $j$ and so  $F_{i+1}$ is finite rigid with trivial stabilizer.
\end{proof}

To produce the finite rigid exhaustion of $\mathcal{N}(S)$ we are going to use the previous lemma. In this direction, we enlarge $F_R$ into a set $F_{1}$ and provide a set of generators for $\mcg(S)$.

  \subsection{Enlarging the finite rigid set}\label{subsec:enlarging_finite_rigid_set_compact}

  Let $\iota \in \mcg(S)$ be the back-front orientation reversing involution of $S$. We define the set of curves $A := A_1 \cup A_2$ where
  \begin{itemize}
    \item \[A_1 := \bigcup_{k=1}^{g-1} \partial(c_k, p_{k+1}, c_{k+1}),\]
    \item and $A_2 = \{nl_{k}, nr_{k}|\; k\in \{2, \dots, g-1\}\}$, so that $nl_{k}, nr_{k}$ are curves  as in Figure \ref{fig:A2_nopuncs}.
  \end{itemize}

  To distinguish curves in $A_1$,  define $c_{k,k+1}$ as in Figure \ref{fig:A2_nopuncs} so that   \[\partial(c_k, p_{k+1}, c_{k+1}) = \{c_{k,k+1}, \iota  (c_{k,k+1})\}.\]

  \begin{figure}[h!]
    \centering
    \begin{subfigure}{.45\linewidth}
      \centering
      \includegraphics[width=0.8\linewidth]{img/ckk.JPEG}
      \caption{Curves in $A_1$.}
      \label{fig:A1_nopuncs}
    \end{subfigure}
    \begin{subfigure}{.45\linewidth}
      \centering
      \includegraphics[width=0.8\linewidth]{img/nlk.JPEG}
      \caption{Curves in $A_2$.}
      \label{fig:A2_nopuncs}
    \end{subfigure}
    \caption{Curves in $A$ for a closed surface.}
  \end{figure}

  \begin{lemma}\label{lemma:enlarge_fr_compact}
    Let $S$ be a closed surface of genus $g\geq 3$. The subcomplex spanned by $F_R \cup A \subset \mathcal{N}(S)$ is a finite rigid set with trivial pointwise stabilizer.
  \end{lemma}
  \begin{remark}
    In the  argument below we sometimes abuse notation using $ p_1^+= p_1^- = p_1$ and $ p_g^+=  p_g^- = p_{g+1}$.
  \end{remark}
  \begin{proof}
    Take $\phi: F_R \cup A \to \mathcal{N}(S)$ a locally injective simplicial  map. By  Theorem \ref{thm:fr} in the closed case, there is an $h\in \mcg(S)$ such that $h\circ \phi$ fixes $F_R$; we rename $h\circ \phi$ to $\phi$. Furthermore, the subcomplex $F_R \cup A$ has diameter two, so $\phi$ is injective.

    First, we  check that $A_1$ is fixed by $\phi$. Note that $ \phi(\iota (c_{1,2}))$ is contained in the pair of pants bound by the curves \[c_1, c_2, c_3, p_2, p_3^+, p_3^-.\] Also, observe that $\phi(\iota (c_{(1,2)}))$ is disjoint from the curve $nd$. As a consequence,  we have $\phi(\iota (c_{1,2}))=\iota ( c_{1,2})$.  On the other hand, $\phi(c_{1,2})$ is contained in the same pair of pants and is disjoint from $\phi(\iota(c_{1,2}))=\iota(c_{1,2})$, thus $\phi(c_{1,2})=c_{1,2}$.

    By an obvious modification of the above argument one checks inductively that \[\phi(c_{k,k+1}) = c_{k,k+1}\text{ and }\phi(\iota  (c_{k,k+1}))=\iota(c_{k,k+1}),\]  for $k\leq g-1$.

    We are left to check that $A_2$ is also fixed by $\phi$. Take   $nr_k\in A_2$; we have that $\phi(nr_k)$ is contained in the pair of pants bound by \[{p_{k-1}^-}, {p_{k+1}^-}, {u_k}, c_{k+1},\, \iota ( c_{k,k+1}).\] Two of the boundaries of the pair of pants are already  curves in $F_R\cup A_1$. From the injectivity of $\phi$, we conclude that $\phi(nr_k)= nr_k$. For $nl_k \in A_2$ the argument is analogous but changing $c_{k+1}, \iota  (c_{k,k+1})$  for $c_{k-1}, \iota(c_{k-1,k})$.

    We have proven that if $\phi$ fixes $F_R$, then it fixes $F_R \cup A$. The statement follows immediately.
  \end{proof}

  We define $F_{1}:= F_R \cup A$ and proceed to prove that it satisfies hypothesis of Lemma \ref{lemma:create_exh}.

  \subsection{Constructing the exhaustion for closed surfaces}

  Let $\iota$ be the back-front orientation reversing involution and let $\delta_\alpha$ be the right Dehn twist along the curve $\alpha$. The set of Dehn twists \[H := \{\delta_{p_1}, \delta_{p_2}, \dots, \delta_{p_{g+1}}, \delta_{{p_2^-}}\} \cup \{\delta_{c_1}, \dots, \delta_{c_k}\}\] are known as the \emph{Humphries generators}, which are known to generate the group of orientation preserving mapping classes $\mcgo(S)$  \cite{humphries_generators_1979}. Hence, $H \cup \{\iota\}$ generates $\mcg(S)$.

  \begin{lemma}\label{lemma:fr1_as_in_lemm}
    Let $h\in H\cup \{\iota\}$, the set $F_{1} \cup h(F_{1})$ is a finite rigid set with trivial pointwise stabilizer.
  \end{lemma}
  \begin{proof}
    First, we prove it for $h=\delta_{p_1}$. Let $\phi: F_{1} \cup h(F_{1}) \to \mathcal{N}(S)$ be  any locally injective simplicial  map.

    Since $F_{1}$ is a finite rigid set, we may assume that $\phi$ fixes $F_{1}$ by precomposing with a mapping class. Moreover, since $h(F_{1})$ is also finite rigid, there exists a mapping class $f\in \mcg(S)$ such that \[\phi|_{h(F_{1})}= f|_{h(F_{1})}.\]

    Proving $F_{1} \cup h(F_{1})$ is a finite rigid set with trivial pointwise stabilizer  boils down to prove that $f = 1 \in \mcg(S)$.

    Recall that $p_1$ is the  associated curve to the Dehn twist $h=\delta_{p_1}$. Now, let $S' = S\setminus p_1$ and consider the well-known cutting homomorphism (see \cite[Proposition 3.20]{farb_primer_2012}) \[1 \rightarrow \langle \delta_{p_1} \rangle \rightarrow \mcgo(S, p_1) \rightarrow \mcgo(S'), \]
    where $\mcgo(S') \subset \mcg(S')$ is the subgroup of orientation preserving classes and $\mcgo(S,p_1) \subset \mcg(S)$ is the subgroup of orientation preserving  classes that fix $p_1$. Notice that $f$ fixes all the curves in $F_{1} \cap h(F_{1})$,  which  fill $S'$. In particular, $f$ is orientation preserving and fixes $p_1$. Furthermore, by means of the Alexander method, the image of $f$  by the cutting homomorphism is trivial and the above sequence implies that $f=\delta_{p_1}^k$, for some $k\in \mathbb{Z}$. We are left to see that $k=0$.

    Note that $i\left(nl, \delta_{p_1}(c_{g+1})\right)=0$. As $\phi$ is locally injective, we know that $i\left(\phi(nl), \phi\left(\delta_{p_1}(c_{g+1})\right)\right)=0$, which is equivalent to
    \begin{equation}\label{eq:intersect_0}
      i\left(nl, \delta_{p_1}^{k+1}(c_{g+1})\right)=0,
    \end{equation}
    since $\phi|_{F_{1}}=\text{id}$ and $\phi|_{h(F_{1})} = \delta_{p_1}^k$.

    It can be directly checked that   Equation (\ref{eq:intersect_0}) is satisfied if and only if $k=0$, thus proving the statement of the lemma for $h=\delta_{p_1}$.

    The rest of the cases $h\in H$ are proved in exactly the same way,  but changing  the curves in Equation (\ref{eq:intersect_0}). We list all the cases for completeness:

    \begin{itemize}
      \item If $h=\delta_{p_{g+1}}$, change   $(nl, c_{g+1})$ in (\ref{eq:intersect_0}) by $(c_{g+1}, nr)$;

      \item If $h=\delta_{p_i}$ for $i\in\{2,\dots, g-2\}$, change $(nl,c_{g+1})$ by $(nl_i, c_{i,i+1})$;

      \item If $h=\delta_{p_{g-1}}$, change $(nl,c_{g+1})$ by  $(c_{g-2,g-1}, nr_{g-1})$;

      \item If $h=\delta_{{p_2^-}}$, change $(nl,c_{g+1})$ by $(c_{g+1}, nr_2)$;

      \item If $h=\delta_{c_k}$ for $k\in \{1,\dots, g-1\}$, change $(nl,c_{g+1})$ by $(p_{k+1}, nr_{k+1})$;

      \item If $h=\delta_{c_g}$, change $(nl,c_{g+1})$ by $(nl_{g-1}, p_g)$.

    \end{itemize}

    To finish the proof, we need to consider the case $h=\iota$. In this case, $F_{1} \cap h(F_{1})$ contains the trivially pointwise stabilized set $P\cup C  \cup A_1$, so it follows immediately that $f=1\in \mcg(S)$.
  \end{proof}

\begin{proof}[Proof of Theorem \ref{thm:exh} for closed surfaces]
  Let $S$ be a closed surface of genus $g\geq 3$. Consider $F_{1}:=F_R\cup A$ and the set of generators $H\cup\{\iota\}$ of the extended mapping class group $\mcg(S)$. By Lemma \ref{lemma:create_exh} we have the desired exhaustion, where the hypotheses have been checked in lemmas \ref{lemma:enlarge_fr_compact} and \ref{lemma:fr1_as_in_lemm}.
\end{proof}

\section{Finite rigid sets for punctured surfaces}\label{sec:fr_puncs}

Let $S=S_{g,n}$ with $n\geq 1$ and  $g\geq 3$. In this section we construct a finite rigid set $F'_R\subset \mathcal{N}(S)$ with trivial pointwise stabilizer. As we will see, the argument to prove the rigidity of $F'_R$ is morally the same  as the one in Section \ref{sec:fr_no_puncs}, although  more involved as it requires to manipulate more curves.

\subsection{Constructing the finite rigid set}
The subcomplex $F'_R$ is spanned by the following curves:

\begin{itemize}
  \item   $P$ be the pants decomposition as in Figure \ref{fig:pant_decomposition_with_puncs}. Note that, in contrast with the closed case, one needs to add the curves $\{p_{2,0}^+, \dots, p_{2,n}^+\}$.
  \item The analogous sets $C$, $U$, $D$, $L$, $R$ and $N$ as in the closed case (see figures \ref{fig:c_with_puncs}, \ref{fig:ctilde_with_puncs}).
  \item To detect the non adjacency rel to $P$ near the punctures, we add the sets of `puncture left'  curves \[Pl:=\{pl_1, \dots, pl_n\}\] and `puncture right' curves \[Pr := \{pr_1, \dots, pr_n\},\] as in figures \ref{fig:left_curves_with_puncs} and \ref{fig:right_curves_with_puncs}.
  \item Lastly, let $\iota$ be the back-front orientation reversing involution and consider the set of curves \[C_* := \{c_{1,2}, c_{2,g},  \iota( c_{1,2}), \iota( c_{2,g})  \},\] where $c_{1,2}$ and $c_{2,g}$ are as in \ref{fig:cstar}.
\end{itemize}

\begin{figure}[h!]
  \centering
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/pants_p_2.JPEG}
    \caption{Pants decomposition $P$ for $S_{g,2}$.}
    \label{fig:pant_decomposition_with_puncs}
  \end{subfigure}
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/c_p.JPEG}
    \caption{Curves in  $C$ for $S_{g,3}$.}
    \label{fig:c_with_puncs}
  \end{subfigure}\par \medskip

  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/ud_p_2.JPEG}
    \caption{Up and down curves  $u_2, d_2$  for $S_{g,3}$.}
    \label{fig:ctilde_with_puncs}
  \end{subfigure}
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/pl_2.JPEG}
    \caption{Curves $pl_1,pl_2, pl_3$ for $S_{g,3}$.}
    \label{fig:left_curves_with_puncs}
  \end{subfigure}\par\medskip

  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/pr_2.JPEG}
    \caption{Curves $pr_1,pr_2, pr_3$ for $S_{g,3}$.}
    \label{fig:right_curves_with_puncs}
  \end{subfigure}
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/cstar.JPEG}
    \caption{Curves $c_{1,2}$ and $c_{2,g}$ for $S_{g,3}$.}
    \label{fig:cstar}
  \end{subfigure}

  \caption{Curves in $F'_R$. Punctures are marked as small crosses on the top of the surface.}
\end{figure}

The finite rigid set $F'_R$ is the maximal subcomplex of $\mathcal{N}(S)$ spanned by the vertices \[P \cup C\cup U \cup D \cup L\cup R \cup N \cup Pl \cup Pr  \cup C_*.\]

\begin{remark}
  Note that the subcomplex  $F'_R$  has diameter two. Thus, any locally injective simplicial  map $\phi: F'_R \to \mathcal{N}(S)$ is injective.
\end{remark}

The following lemmas prove the finite rigidity of $F'_R$.

\begin{lemma}\label{lemma:fr2_as_in_lemm}
  Let $S$ be a punctured surface of genus $g\geq 3$. For any locally injective simplicial  map $\phi: F'_R \to \mathcal{N}(S)$, there exists $h\in\mcg(S)$ such that $h|_P=\phi|_P$.
\end{lemma}
\begin{proof}
  First, notice that we can extend Lemma \ref{lemma:compact_non_adj_rel_p} to the case of punctured surfaces, and the proof works with minor changes.

  Lemma \ref{lemma:compact_adj_rel_p} can also be extended to punctured surfaces. The proof for once punctured surfaces is similar to the closed case. Here we sketch the proof for surfaces with  $n>1$ punctures:

  Using Remark \ref{rmk:at_least_adj_curves}, it is straightforward to deduce that the curve $p_{2,i}^+$ is adjacent rel to $P$  to $p_{2,i-1}^-$ and $p_{2,i+1}$, for $i\in \{1,\dots, n-1\}$. As a consequence of these adjacencies, we deduce that $p_{2,0}^+$ and $p_{2,n}^+$ bound a subsurface with two boundary components and $n$ punctures. It follows that $p_{2,0}^+$ is adjacent rel to $P$ to at least three curves. On the other hand, the non adjacency rel to $P$ of $p_{2,0}^+$ implies that it is adjacent to at most three curves. Thus, $p_{2,0}^+$ is adjacent to exactly three curves, namely $p_{2,1}^+, p_1$ and $p_2$. The rest of the adjacencies follow  just as in the proof of Lemma \ref{lemma:compact_adj_rel_p}.

  Once we know $\phi$ preserves adjacency rel to $P$, we can use Corollary \ref{lemma:fr_top_typ} to produce  a mapping class $h\in \mcg(S)$ with $h|_P=\phi|_P$.
\end{proof}

The next lemma proves that we may choose $h\in \mcg(S)$ to coincide with $\phi$ on all the curves of $F'_R$.

\begin{lemma}\label{lemma:fr2_curve_characterize}
  Let $S$ be a punctured surface of genus $g\geq 3$. For any locally injective simplicial  map $\phi: F'_R \to \mathcal{N}(S)$ there exists $h\in\mcg(S)$ such that $\phi = h|_{F_R'}$.
\end{lemma}
\begin{proof}
   The idea is  to progressively detect intersections between curves and, by composing with Dehn twists along $P$, construct a mapping class that coincides with $\phi$ on those curves.

  First, notice that by Lemma \ref{lemma:fr2_as_in_lemm} there exists $h\in \mcg(S)$ such that $h\circ \phi$ fixes $P$ pointwise; rename $h \circ \phi$ as $\phi$.

  Next, we may use the same argument of Lemma \ref{lemma:aaa} to detect the following intersections:
  \begin{itemize}
    \item intersection of curves in $U\cup D$ with curves in $P$,
    \item intersections of curves in $Pl$ with curves in $P$,
    \item intersections of curves in $Pr$ with curves in $P$, and
    \item $c_k$ with curves in $P$ for $k\in \{2, \dots,g-1\}$.
  \end{itemize}
  The arcs that these intersections yield characterize the image by $\phi$ of curves in $U$, $D$ and  $\{c_2,\dots, c_{g-1}\}$. Now, by composing with Dehn twists along $P$, we may assume $\phi$ fixes the curves in $U$, $D$ and  $\{c_2,\dots, c_{g-1}\}$ (see Lemma \ref{lemma:aaa} for an analogous argument). It  follows that  $Pl$ and $Pr$ are also fixed.

  Now, note that $\phi$ detects the  following intersections:
  \begin{itemize}
    \item curves in $C_*$ with  curves in $P$,
    \item curves in $\{c_1,c_g\}$ with curves in $P$.
  \end{itemize}
  For instance, consider $c_{1,2}\in C_*$ and $p\in P$ disjoint from $c_{1,2}$. If $\phi(c_{1,2})$ was disjoint from $p$, then $\phi(c_{1,2})$ would have to intersect either the curve  $\phi(c_1),\phi(c_2)$ or $\phi(\iota(c_{2,g}))$, leading to a contradiction. Thus, $\phi(c_{1,2})$ and $p$ intersect. The rest of the cases follow similarly.

  Using the above intersections and fixed curves, we now focus on determining the curves in $\phi(C_*)$.

  To characterize $\phi(c_1)$ (resp. $\phi(c_g)$) note that it is  contained in the subsurface $S'=S_{1,2}$ bound by the curves $p_2^-, p_2^+$  (resp. by $p_{g-1}^-,p_{g-1}^+$). Additionally,   since $\phi(c_1)$ is disjoint from the arcs $a_1=S'\cap \phi(c_{1,2})$ and $a_2= S' \cap \phi(c_2)$ (resp. $S'\cap \phi(c_{2,g})$ and $S' \cap \phi(c_{g-1})$), we have that $\phi(c_1)$ is contained in the annulus $S'\setminus \bigcup a_i$. It follows that $\phi(c_1)$ is the unique curve in the annulus (resp. $\phi(c_g)$). We may  again consider a mapping class $h\in \mcg(S)$ that is a composition of  twists along curves in $P$ such that  $h\circ \phi(c)=c$ for $c\in \{c_1, c_g\}$; we rename $h\circ \phi$ to $\phi$.

  For $c_{1,2}\in C_*$, note that $\phi(c_{1,2})$  is contained in a subsurface $S' = S_{2,2}$ bound by $\phi(pr_1)$ and $p^-_3$ (or $p_4$ if $g=3$). If we also consider the arcs $S'\cap \{\phi(c_1),p_2,\phi(c_2),\phi(c_3)\}$, we have that $\phi(c_{1,2})$ is contained in a pair of pants.  Thus, $\phi(c_{1,2})$ corresponds to a curve isotopic to one of the boundaries of the pair of pants. One of the boundaries is a separating curve, so either $\phi(c_{1,2})=c_{1,2}$  or $\phi(c_{1,2})=\iota(c_{1,2})$.  These two alternatives are related by the involution $\iota$.  Thus, by precomposing with $\iota$ we can assume $\phi$ fixes $c_{1,2}.$

  It is now possible to check, by similar arguments, that the curves in $\{ \iota(c_{1,2}), \iota( c_{2,g}), nl,nr, nd \} \cup L \cup R$ are also fixed by $\phi$. Thus, we have found a mapping class $h\in \mcg(S)$ such that $h\circ \phi$ fixes $F'_R$ and the statement follows.
\end{proof}

We have essentially completed the proof of Theorem \ref{thm:fr}.

\begin{proof}[Proof of Theorem \ref{thm:fr} for surfaces with punctures]
  Let $\phi: F_R' \to \mathcal{N}(S)$ be a locally injective simplicial  map, Lemma \ref{lemma:fr2_curve_characterize} provides the mapping class inducing $\phi$.

  The uniqueness of the mapping class follows as in the closed case.
\end{proof}

\section{Finite rigid exhaustion for punctured surface}\label{sec:exh_puncs}

Let $S$ be a punctured surface of genus $g\geq 3$. In this section we construct a sequence $F'_{1} \subset F'_{2} \subset  \dots \subset \mathcal{N}(S)$ such that each $F'_{i}$ is a finite rigid set with trivial pointwise stabilizer and \[\bigcup_{i=1}^\infty F'_{i} = \mathcal{N}(S).\]

The strategy to construct the exhaustion is the same as in the closed case (see Section \ref{sec:exh_no_puncs}). First, we are going to enlarge the finite rigid set $F'_R$  to $F'_{1}$ and then use  Lemma \ref{lemma:create_exh} to construct the exhaustion.

\subsection{Enlarging the finite rigid set}

First, we enlarge $F'_R$. Consider the set of curves $A' := A_1 \cup A_2 \cup A_3$, where the sets $A_1$ and $A_2$ are complete analogues to the closed case (see section \ref{subsec:enlarging_finite_rigid_set_compact} for definitions), and $A_3$ is the set of  curves $\{a_k |\; k \in \{1,\dots,n\}\}$ as in Figure \ref{fig:a3_with puncs}.

\begin{figure}[h]
  \centering
  \begin{subfigure}{.45\linewidth}
    \centering
    \includegraphics[width=0.8\linewidth]{img/a_2.JPEG}
    \caption{Curves $a_1,a_3$ in $A_3$ for $S_{g,3}$.}
    \label{fig:a3_with puncs}
  \end{subfigure}\par\medskip
\end{figure}

\begin{lemma}\label{lemma:almostlast}
  The set $F'_R \cup A'$ is finite rigid with trivial pointwise stabilizer.
\end{lemma}
\begin{proof}
  Let $\phi:F'_R \cup A' \to \mathcal{N}(S)$ be a locally injective simplicial  map. By precomposing with a mapping class we may assume that $\phi$ fixes $F'_R$ pointwise.

  First, we prove that $A_1$ is also fixed by $\phi$. The curves $c_{1,2}, \iota( c_{1,2}) \in A_1$ are already in $C_* \subset F_R'$, so they are fixed by $\phi$. For $c_{2,3} \in A_1$, notice that $\phi(c_{2,3})$ is disjoint from \[\Lambda = l_n\cup p_1\cup c_1\cup p_4^+\cup p_4^-\cup c_4\cup c_2\cup c_3\cup \iota(c_{1,2}) \cup \iota( c_{2,g}).\]As a consequence,  $\phi(c_{2,3})$ is contained in a pair of pants of $S\setminus \Lambda$, and it follows that  $\phi(c_{2,3})=c_{2,3}$. A similar argument works for $\iota(c_{2,3})$. For the rest of $A_1$,  one can proceed as in the closed case (see Lemma \ref{lemma:enlarge_fr_compact}).

  To prove $A_2$ is fixed, the argument as in the closed case also applies(see Lemma \ref{lemma:enlarge_fr_compact}).

  To finish the proof we must show that $a_k \in A_3$ is  fixed. To check this, note that $\phi(a_k)$ is  disjoint from \[\Lambda' = l_{k}\cup  r_{k+1}\cup p_1\cup c_1\cup {p_3^-}\cup c_3\cup c_2\cup \iota( c_{1,2})\cup \iota( c_{2,3}).\] As a consequence, $\phi(a_k)$ is contained in a pair of pants of $S\setminus \Lambda'$, and it follows that $\phi(a_k)=a_k$. Thus, $A'$ is fixed and $F'_R \cup A'$ is  a finite rigid set  with trivial pointwise stabilizer.
\end{proof}

We  define $F'_{1} := F'_R \cup A'$.

\subsection{Constructing the exhaustion for punctured surfaces}

The goal of this section is to construct an exhaustion of $\mathcal{N}(S)$ by finite rigid sets with trivial pointwise stabilizers. In this direction, we will consider a set of generators of $\mcg(S)$ such that the subcomplex $F_1'$ satisfies hypotheses of Lemma \ref{lemma:create_exh}. We are going to assume $S=S_{g,n}$ with $n>0$ punctures.

Let $\iota$ be the back-front orientation reversing involution, consider the usual Humphries generators \[ H' = \{\delta_{p_1}, \dots, \delta_{p_{g-1}}, \delta_{p_2^-}\} \cup \{\delta_{p_{2,i}^+}|\; 0\leq i \leq n\} \}\] and the half twists \[ \{h_{(k,k+1)} | 1\leq k \leq n-1\}\] where $h_{(k,k+1)}$ is the half twist that permutes the puncture $k$ with the puncture $k+1$ (ordering the punctures from left to right). It is well known that  $H'\cup \{\iota\} \cup \{h_{(k,k+1)} | 1\leq k \leq n-1\}$ generates $\mcg(S)$ (see \cite[Chapter 4.4.4]{farb_primer_2012}).

\begin{lemma}\label{lemma:last}
  For every $h\in H'\cup \{\iota\} \cup \{h_{(k,k+1)} | 1\leq k \leq n-1\}$, the set $F'_{1}\cup h ( F'_{1})$ is finite rigid with trivial pointwise stabilizer.
\end{lemma}
\begin{proof}
  The proof is analogous to the closed case (see Lemma \ref{lemma:fr1_as_in_lemm}) and works directly for $h=\iota$, $h = \delta_{p_j}$, $h=\delta_{c_j}$ or $h =\delta{ {p_2}^-}$.  We sketch the rest of the cases:

  Recall that given $h=\delta_x$ and $\phi: F'_{1}\cup h(F'_{1}) \to \mathcal{N}(S)$, we can assume that $\phi$ fixes $F'_{1}$ and $\phi|_{h(F_{1})}=\delta_x^k|_{h(F_{1})}$. Thus, the proof is a matter of checking that $k=0$.

  For $h=\delta_{p_{2,j}^+}$ with $j\leq n-1$, we can consider the curves $l_j, a_j$ and plug them into  Equation (\ref{eq:intersect_0}). It follows that this is satisfied if and only if $k=0$. For $h= \delta_{p_{2,n}^+}$, one uses the curves $r_n, a_n$ in the same equation.

  The only thing left to check  is the case $h=h_{(k-1,k)}$, which can be proved using the curves $a_{k},r_k$ in Equation (\ref{eq:intersect_0}).
\end{proof}

We now complete the proof of Theorem \ref{thm:exh}.

\begin{proof}[Proof of Theorem \ref{thm:exh} for punctured surfaces]
  The Lemmas \ref{lemma:almostlast} and \ref{lemma:last} ensure that $F'_{1}$ satisfies the hypothesis of Lemma \ref{lemma:create_exh}, which in turn produces the desired exhaustion.
\end{proof}

\printbibliography
\nocite{*}

\end{document}

redpajama_set_name: RedPajamaArXiv


Bridgid Bergin is very excited to join ICE after graduating from Wesleyan University with her M.A. in Ethnomusicology. Her thesis, "Indian Fusion Music in NYC: Navigating Space, Place, and Identity," questions notions of identity, space, and place as well as definitions of genre and community. Overall, her research has focused on South Indian music, gender and music, urban theory, and space/place. With her background in Ethnomusicology and non-profit cultural institution work, she has a passion for the sustainment and preservation of the arts as well as creating connections to a larger cross-cultural network via various art forms.
At Wesleyan she was a Teaching Assistant for South Indian music classes, music theory, and gender and music courses, and worked in the World Music Archives. She completed her B.M. in Musical Studies with Advanced Honors at the Crane School of Music, where she studied viola with Dr. Shelly Tramposh. Her Presidential Scholars project and undergraduate thesis focused on female identity in Carnatic music, focusing on the veena and female veena players. As a violist, she has performed in small chamber ensembles in NY and CT and was a member of the Crane Symphony Orchestra and Wesleyan University Orchestra. She has studied Carnatic voice with B. Balasubrahmaniyan and continues to study veena with Nivedita ShivRaj. She has also played in a variety of ensembles including: Potsdam Okuma Taiko (co-founder), Potsdam West African drumming ensemble, and Wesleyan Gamelan ensemble.


Welcome to the latest 2018 edition of our Top 100 for England. Since May, we've produced seven regional charts for East Midlands, West Midlands, North East, North West, South West, East and South East England and these listings now dovetail into the overall national standings that we present below.
We've been publishing an English Top 100 for more than a decade now – this is the 7th biennial ranking list that we've announced – so we're pretty confident that we're giving due recognition to the very best golf courses around the nation, no matter their remoteness or popularity.
At the top of the chart, there's very little movement in the top ten positions, with only Ganton (at #8) swapping places with Woodhall Spa's Hotchkin course (at #9). In fact, since 2006, only a dozen courses have ever appeared at this elite level. Back then, Royal Liverpool occupied the number 3 position and Wentworth (West) was at number 8 but these two courses have since fallen away, replaced in the Top 10 by Sunningdale (New) (currently #4) and Swinley Forest (at #6).
All of which means Royal St George's remains the number 1 course in England, a position it's held since 2012. Venue for the first Open played outside Scotland in 1894 when JH Taylor won the 35th edition of the event, the historic Kent links will host the Open for the fifteenth time in 2020, with Darren Clark trying to replicate his winning performance of 2011 when he became Champion Golfer of the Year at Royal St George's.
Just outside the Top 10 tier, four courses make significant upward moves. The first of these is the Church course at St Enodoc in Cornwall (up three to number 11), which reviewers in the last few months have described as "a beautiful links and yet another wonderful James Braid design… the most dramatic course in GB&I… a little piece of golfing heaven".
Rising four places to number 12, the course of West Sussex at Pulborough sits on the edge of the South Downs National Park, where Sir Guy Campbell and Major C K Hutchison laid out the fairways in 1930. The open heath is no longer in evidence due to the growth of trees down the years but new sites for heather regeneration have been identified and a number of strategically placed bunkers have been introduced in recent times to make this one of the most testing par 68 courses you will ever play.
Also advancing three slots to number 19, Notts Golf Club at Hollinwell in Nottinghamshire has worked hard in recent times with the presentation of its wonderful 18-hole layout, managing the rough, removing gorse and trees, developing areas of heather and embarking on a scheme to install heathland-style bunkers, all of which have contributed towards the club's stated aim of having a tournament–quality course available for play on a daily basis.
The West course at Wentworth in Surrey was roundly criticised for the major alterations made to the layout in 2009. Following another round of extensive (and expensive) renovation work last year, which included the redesign of five greens, the removal of certain bunkers and the installation of a sub-air system on new bent grass greens, the course now reverses a substantial fall of fourteen places in 2014 by climbing six positions to number 20.
Rising seven to number 49, the Championship course at Aldeburgh in Suffolk boasts an enviable architectural pedigree, with John Thompson, Willie Fernie, Willie Park Jnr, JH Taylor and Harry Colt all having a hand in its development since the club was founded back in 1894. From the back tees, the par for the course is set at 68, five strokes less than the standard scratch score, so visiting golfers should pay attention to the notice on the club's website which states: "every hole presents an examination in shot making and accuracy".
In the bottom half of the Top 100 chart, two courses surge an impressive nine places up the listings: the West course at Saunton in Devon (at number 56), where Tom Mackenzie's recent makeover has been very well received, and the Colt & Alison nines at Stoke Park in Buckinghamshire (at number 72), which have just undergone an outstanding bunker renovation by specialist construction firm John Greasley.
The biggest jump up the chart is made by Stoneham in Hampshire, up thirteen to 81. The club has embarked on "Project 2020" to maximize the full potential of this old Willie Park Jnr track, with Ken Moodie directing operations. Thousands of trees have been removed and a heathland restoration plan implemented by John Nicholson. A complete bunker refurbishment programme is also well under way which will deliver a layout fit for golf in the new millennium, more than a hundred years after the club was founded.
There's a handful of new entries in our revised table – London Club (Heritage), Northamptonshire County, Frilford Heath (Red), Hallamshire and Royal Cromer all make way – and you might think that all five newcomers would come from the twenty-five main contenders highlighted in an article entitled The Second Hundred Golf Courses of England 2016 that we published two years ago. Well, the first four courses arrive from that shortlist, with the last one making what some might consider to be an unexpected re-appearance ten years after it dropped out.
The highest new entry at number 86 is actually a re-entry because it was previously listed between 2008 and 2014. The course at Berwick Upon Tweed Golf Club (known locally as Goswick Links) in Northumberland is a James Braid remodelled layout from the early 1930s that appears to be accumulating an ever-growing list of admirers if comments from recent reviews are anything to go by: "to miss out on playing Goswick is to miss out on a seriously good course… a must play for fans of serious links golf… an unexpectedly rewarding experience that offers quite exceptional value for money".
Another re-entry, having made a fleeting appearance in our 2008 chart at number 100, the course at Royal Wimbledon in London (new at number 92) belongs to the third oldest golf club in England, established in 1865. Willie Park Jnr laid out the club's first course in 1907 (prior to that year club members had played on Wimbledon Common with members from London Scottish GC) before Harry Colt redesigned the layout in 1924. Tom Mackenzie has just embarked on an upgrade project to remove trees, regenerate heather, re-position bunkers, restore green sizes and install new tees, with the first tranche of work due for completion next month.
A further Willie Park Jnr design, Huntercombe in Oxfordshire, makes it into the Top 100 for the first time at number 94 and the architect actually owned this course, along with surrounding land intended for real estate development that never happened, which lost him a substantial amount of money. Opened for play in 1901, Huntercombe is a historically important course that has entertained golfers for well over a century now, though the playing corridors nowadays are a lot tighter now than they once were.
The last new name in our Top 100 roll of honour for England at number 99 is Royal Worlington & Newmarket in Suffolk, which last appeared in our national chart in 2006 and 2008. Top Dunn laid out this 9-hole course in 1893 and it's been the home club to the Cambridge University golf team, the Light Blues, ever since then. The ranking merits of this course might be a cause for debate among some golfers who've played "The Sacred Nine" but one thing's for sure, there can be no denying the quality of the putting surfaces, setting this course apart from many others.
We look forward to receiving some feedback when we publish a new national ranking chart so feel free to let us know what you think about our new Top 100 for England. Have we missed out on a course that should be included or maybe we've listed one that has no right to be in such a prestigious list? Perhaps a course is riding too high or languishing too low in the standings? Please click the "Respond to this article" link at the bottom of the page if you'd like to contact us.
To view the complete detailed list of the Top 100 Golf Courses of England click the link.
I've been fortunate enough to play 13 of these courses this year (and one of those that has dropped off the list), all of which thoroughly deserve their places. Of the movers, I'd certainly agree with both St Enodoc and Deal climbing ahead of Saunton East, and it's good to see Hollinwell climbing into the top 20. My one disappointment is Sherwood Forest being one of the biggest fallers. I'm sure I'm biased as a member for over 30 years but if the comments on this site are anything to go by, I don't think I'm the only one who thinks that it was lower than it deserved even in its previous position.
As a member of Hadley Wood GC, I look forward to our 2019 rankings improving with the appointment of our new head green-keeper who is transforming what is a wonderful course into a truly spectacular course.
Disappointed to see Northamptonshire County drop out of the top 100.
The course has hosted amateur and professional events and will again hold Open qualifying from 2018.


text:
using System;
using FakeItEasy;
using Xunit;

using FluentAssertions;

namespace GitHubSearch.Specs
{
    public class FileCacheSpecs
    {
        private static readonly string RelativeCacheFolder = "\\GitHubSearch\\Cache";

        private static readonly string AbsoluteCacheFolder =
            $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}{RelativeCacheFolder}";

        [Fact]
        public void When_instantiated_it_should_create_cache_folder()
        {
            // Arrange
            var fileSystem = A.Fake<IFileSystem>();
            A.CallTo(() => fileSystem.DirectoryExists(AbsoluteCacheFolder)).Returns(false);

            // Act
            var fileCache = new FileCache(fileSystem);

            // Assert
            A.CallTo(() => fileSystem.EnsureDirectoryExists(AbsoluteCacheFolder)).MustHaveHappened();
        }

        [Fact]
        public void When_cached_file_does_not_exists_it_should_be_created()
        {
            // Arrange
            var fileSystem = A.Fake<IFileSystem>();
            A.CallTo(() => fileSystem.FileExists(A<string>._)).Returns(false);

            var fileCache = new FileCache(fileSystem);

            var filePath = "SomeFile.txt";
            long repositoryId = 123;
            string repositoryName = "SomeRepo";

            var sha = "8560328effd5fbee640e8aaef79b5ebc7ba1afe5";

            var content = "SomeContent";

            var expectedFilePathPostfix = $"{RelativeCacheFolder}\\{repositoryName}\\{filePath}-{sha}.cache";

            var downloadContentFunc = A.Fake<Func<long, string, string>>();
            A.CallTo(() => downloadContentFunc.Invoke(A<long>._, A<string>._)).Returns(content);

            // Act
            fileCache.GetCachedFileContent(repositoryId, repositoryName, filePath, sha, downloadContentFunc);

            // Assert
            A.CallTo(() => downloadContentFunc.Invoke(123, filePath)).MustHaveHappened();
            A.CallTo(() => fileSystem.WriteAllText(A<string>.That.EndsWith(expectedFilePathPostfix), content)).MustHaveHappened();
        }

        [Fact]
        public void When_cached_file_exists_it_should_be_loaded_from_cache()
        {
            // Arrange
            var fileSystem = A.Fake<IFileSystem>();
            A.CallTo(() => fileSystem.FileExists(A<string>._)).Returns(true);

            var fileCache = new FileCache(fileSystem);

            long repositoryId = 123;
            string repositoryName = "SomeRepo";
            var filePath = "SomeFile.txt";
            var sha = "8560328effd5fbee640e8aaef79b5ebc7ba1afe5";

            var expectedFilePathPostfix = $"{RelativeCacheFolder}\\{repositoryName}\\{filePath}-{sha}.cache";

            string content = "SomeContent";
            A.CallTo(() => fileSystem.ReadAllText(A<string>.That.EndsWith(expectedFilePathPostfix))).Returns(content);

            var downloadContentFunc = A.Fake<Func<long, string, string>>();

            // Act
            var cachedContent = fileCache.GetCachedFileContent(repositoryId, repositoryName, filePath, sha, downloadContentFunc);

            // Assert
            A.CallTo(() => downloadContentFunc.Invoke(A<long>._, A<string>._)).MustNotHaveHappened();

            cachedContent.Should().Be(content);
        }

        [Fact]
        public void When_file_is_downloaded_it_should_clear_old_cache_files()
        {
            // Arrange
            var fileSystem = A.Fake<IFileSystem>();
            A.CallTo(() => fileSystem.FileExists(A<string>._)).Returns(false);

            var fileCache = new FileCache(fileSystem);

            int repositoryId = 123;
            string repositoryName = "SomeRepo";

            string filePath = "SomeFile.txt";

            string oldSha1 = "8560328effd5fbee640e8aaef79b5ebc7ba1afe5";
            string oldSha2 = "6ce7bf64673d40e7b5b3d13f4f1f992c1ea37119";
            string newSha = "b12351820c868918f4df7cfef35b7bc70a878bd5";

            string oldContent = "SomeOldContent";
            string newContent = "SomeNewContent";

            string oldCacheFile1 = $"{RelativeCacheFolder}\\{repositoryName}\\{filePath}-{oldSha1}.cache";
            string oldCacheFile2 = $"{RelativeCacheFolder}\\{repositoryName}\\{filePath}-{oldSha2}.cache";
            string newCacheFile = $"{RelativeCacheFolder}\\{repositoryName}\\{filePath}-{newSha}.cache";

            string repositoryCacheDirectory = $"{RelativeCacheFolder}\\{repositoryName}";
            A.CallTo(() => fileSystem.EnumerateFiles(A<string>.That.EndsWith(repositoryCacheDirectory), A<string>._))
                .Returns(new [] { oldCacheFile1, oldCacheFile2 });
            A.CallTo(() => fileSystem.ReadAllText(A<string>.That.EndsWith(oldCacheFile1))).Returns(oldContent);
            A.CallTo(() => fileSystem.ReadAllText(A<string>.That.EndsWith(oldCacheFile2))).Returns(oldContent);

            var downloadContentFunc = A.Fake<Func<long, string, string>>();
            A.CallTo(() => downloadContentFunc.Invoke(A<long>._, A<string>._)).Returns(newContent);

            // Act
            fileCache.GetCachedFileContent(repositoryId, repositoryName, filePath, newSha, downloadContentFunc);

            // Assert
            A.CallTo(() => downloadContentFunc.Invoke(A<long>._, A<string>._)).MustHaveHappened();
            A.CallTo(() => fileSystem.DeleteFile(A<string>.That.EndsWith(oldCacheFile1))).MustHaveHappened();
            A.CallTo(() => fileSystem.DeleteFile(A<string>.That.EndsWith(oldCacheFile2))).MustHaveHappened();
            A.CallTo(() => fileSystem.WriteAllText(A<string>.That.EndsWith(newCacheFile), newContent)).MustHaveHappened();
        }

        [Fact]
        public void When_flushing_cache_it_should_clear_all_cache_files()
        {
            // Arrange
            var fileSystem = A.Fake<IFileSystem>();
            A.CallTo(() => fileSystem.FileExists(A<string>._)).Returns(false);

            var fileCache = new FileCache(fileSystem);

            // Act
            fileCache.Flush();

            // Assert
            A.CallTo(() => fileSystem.RemoveFolder(A<string>.That.EndsWith(RelativeCacheFolder))).MustHaveHappened();
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
ALYN Hospital Ensures High Availability for its Critical Applications with SIOS DataKeeper
< 1 minutes
Recent News & Press
How will high availability develop in 2023?
Cassius Rhue, VP of Customer Experience, SIOS Technology, predicts the following major trends in high availability and related areas. 2022 continued the pace of uncertainty […]
SIOS Reveals Technology Predictions for 2023
From Data Democratization to New Requirements for Disaster Recovery and High Availability Protection – Here Are Some of the Biggest Trends SAN MATEO, CA – […]
Disaster Recovery: Avoiding What You Don't See Coming
Nobody anticipated that all the data centers in lower Manhattan would go offline before Super Storm Sandy hit in 2012. But they were—and it was […]
See All News & Press

redpajama_set_name: RedPajamaCommonCrawl


Child labor is a global challenge more then million children are forcibly doing hard work.
During work time they misuse. They do not have right to defense from their law. They continue their work against of labor law. This is a big challenge today more then million dollars are donating to these children's families for changing their life situation but by passing everyday amount of labor child are increasing day by day.
If we collect world wildly 187 million labor child that more than half of them do not have access to education.
Afghanistan is a country which has more than six million labor child that they are do not have access to education, more than these children are going to misuse during work time.
Our school is publishing to help these children by providing them save environment for education with high education standard and with well qualified bachelor teachers and, besides paying amount of salary to support them not to obligate to engage in hard working.
The advantage and benefits which this school create is completely different both from structural and assisting side from others Schools and Organizations which works in this filed.


When choosing someone to spend life with, it's essential to find a person that shares your own hopes, dreams, and aspirations for the future. But what if you don't know what you want your life to look like? This is the question 'Love Finds You in Charm', a new movie on UPtv, seeks to answer.
The romantic drama tells the story of Emma Miller (played by Danielle Chuchran), a young Amish woman from Indiana that leaves her family's farm on a journey to find out who she is, and what she really wants.
This film is meant to be a follow-up to the successful 'Love Finds You in Sugar Creek, Ohio' which aired on UPtv last year. 'Love Finds You in Sugar Creek, Ohio' was based on a book by Serena B. Miller. 'Love Finds You in Charm' is based on a book of the same name by Annalisa Daughety.
At the beginning of the movie, Emma is engaged to an Amish fellow named Jacob, whom is apparently a huge catch in her community. Jacob approaches Emma to let her know that he's decided to officially join "the Church," meaning he will be a part of the Amish community for life and his wife must be as well. Emma responds by telling Jacob that she's going to be leaving their hometown to visit her widowed cousin in Charm, Ohio, indefinitely. Jacob is crestfallen, while Emma is relieved. Thus begins Emma's quest to find her identity outside of the world that she has always known.
Upon arriving at her cousin's farm, Emma meets a handsome Amish farmhand named Noah (a Chris Hemsworth look-alike played by Trevor Donovan.) Noah seems to be everything Emma has ever wanted in a man; he's even read her favorite novel, Pride and Prejudice. Sparks are totally flying between the two of them. But then Emma meets Andy, an exciting and cosmopolitan writer, and suddenly, nothing seems clear to her anymore.
The idea of an Amish woman coming to terms with her identity outside of the Amish way of life is a fascinating one, and ripe with potential. However, we don't get to see much of Emma's exploration as it is limited to a friendship with an Englischer (ie non-Amish person) that she meets in Charm, and her interactions with love-interest Andy.
Danielle Churchran does a decent job of playing the winsome, innocent Emma convincingly. Both Trevor Donovan and Andy's character, Drew Fuller, also get the job done. Tiffany Dupont plays Emma's Englischer friend and is a welcome bright spot of energy in a film that is at times tedious in its formulaic insistence.
While Emma is supposedly out to discover herself, her interests in doing so are vague and without motive. Be wary if watching this film with young girls: in this movie, "discover yourself" is code for "find your husband." Also troubling is the overall message presented by the film, which seems to imply that outside of one's own family and loved ones lies only mal-intentioned people and dangerous situations. Emma doesn't resolve the questions she has about the outside world as much as she makes a choice to intentionally ignore the answers.
Ultimately, 'Love Finds You in Charm' is a girl-meets-boy-and-then-she-meets-another-boy romance that will elicit some smiles, but little passion, from viewers. This wouldn't be so bad if it were not for the potential for the movie to have been about so much more.


The TWN4 MultiTech 3 BLE integrates RFID (125 kHz, 134.2 kHz and 13.56 MHz), NFC and Bluetooth Low Energy capabilities into a compact but powerful reader. Its reduced size combined with excellent read/write performance makes it the perfect reader for all applications where small size and full performance matters.
Furthermore, the TWN4 MultiTech 3 BLE provides access to most common host interfaces such as USB, serial (TTL) or I2C which are readily accessible through an on-board connector.
The TWN4 MultiTech 3 BLE allows users to read and write almost all common worldwide 125 kHz, 134.2 kHz and 13.56 MHz tags and/or labels. It supports all major transponders from various suppliers like ATMEL, EM, ST, NXP, TI, HID etc. and ISO standards like ISO14443A/B (T=CL), ISO15693, ISO18092 / ECMA-340 (NFC).


ASSI Fabricators has selected over 30 colors of Granite, Soapstone and Marble based on market research and the latest trends, and are currently stocking these materials in house. While ASSI offers the fabrication of any color or material, purchasing larger quantities of limited colors allows us to offer lower than market price on those specific materials. Below are the Program Colors that ASSI Fabricators has selected for this calendar year.


Are you financially covered for when the unexpected happens?
Whether you aspire to day-to-day peace of mind, part-time fulfilment, or long-term wealth creation, SDL is the right choice!
If you have any questions, you may send them to us in the message box below and we will get back to as soon as possible.
Who introduced you to SDL?
Which plan suits your needs best?
Are you interested in the Business Opportunity connected to your plan?


British male Voice-Over Artist, Professional Voice Talent and Audio Producer specialising in commercial, promo, e-learning, IVR, voicemail, TV, advertising, radio imaging and more.
As a versatile professional Voice Talent, I can convey voice-over narrations ranging from ages 20 to 50. Styles and delivery include: warm, smooth, articulate, sophisticated, authentic, sincere, guy next door, authoritative, promo, corporate, educational and knowledgeable.
My voice has been described as sounding similar to Tom Hiddleston and Roger Moore (depending on the age, style and delivery etc.).


Twelve-year-old Catherine has spent a lot of time coming up with a list of rules for her autistic brother David to follow to help him act "normal". Despite all of her rules and reminders to David, Catherine is still embarrassed when he acts out. However, when Catherine begins two new friendships over the summer, one with a girl that moves in next door and one with a paraplegic who she meets at David's occupational therapy clinic, she starts to wonder what "normal" really means. Recommended for fans of Wonder by R.J. Palacio and Out of My Mind by Sharon Draper, this realistic novel is for ages 9 and up.


text:
Three men charged after County Durham pub disturbance
Police said the brawl left one man needing hospital treatment
Three men have been charged in connection with a pub brawl which left a reveller with serious head injuries.
Police were called to the Oddfellows Arms in Haswell, near Peterlee, on 10 April after reports of a disturbance.
Two men aged 26 and 24 from Hartlepool and 20-year-old from Leadgate have been charged with conspiracy to commit actual bodily harm with intent.
A fourth man, who is 25 and from Cumbria, remains on police bail pending further inquiries.
A spokesman for Durham Police said a 31-year-old man from Durham had also been charged with possession of a prohibited weapon and possession of ammunition.
This follows the recovery of a handgun in Gateshead, which was found as a result of the initial inquiries into the incident at the Oddfellows Arms.
He is due before Gateshead magistrates in January.
Durham Police


The Hotep System is a system located in the Hotep Sector of the Beta Quadrant.
Hotep IV was settled in the late 2370s by a group of former Federation citizens who were forced out of their homes when their planet was ceded to the Cardassian Union. The settlers rejected Federation offers of resettlement, opting instead to move far away from major populated systems and what they saw as undue interference in their affairs.
Originally "Collateral Damage" took place in the Hotep System. Replaced by the revamped version "A Gathering Darkness", the original mission has been removed from game with the release of Season Nine: A New Accord on 22nd April 2014. Since then the Hotep System solely acts as a door to user-generated missions.
Last modified: 31 January 2016 at 19:22.


text:
import pytest

from supvisors.client.zmqsubscriber import *
from unittest.mock import call, Mock
from zmq import ZMQError

def test_create_logger(mocker):
    """ Test the create_logger method. """
    mocked_stdout = mocker.patch('supervisor.loggers.handle_stdout')
    mocked_file = mocker.patch('supervisor.loggers.handle_file')
    # test default
    default_format = '%(asctime)s;%(levelname)s;%(message)s\n'
    logger = create_logger()
    assert isinstance(logger, loggers.Logger)
    assert logger.level == LevelsByName.INFO
    assert mocked_stdout.call_args_list == [call(logger, default_format)]
    assert mocked_file.call_args_list == [call(logger, r'subscriber.log', default_format, True, 10485760, 1)]
    mocker.resetall()
    # test with parameters
    new_format = '%(asctime)s %(message)s'
    logger = create_logger('/tmp/client.log', LevelsByName.CRIT, new_format, False, 1024, 10, False)
    assert isinstance(logger, loggers.Logger)
    assert logger.level == LevelsByName.CRIT
    assert not mocked_stdout.called
    assert mocked_file.call_args_list == [call(logger, '/tmp/client.log', new_format, False, 1024, 10)]

@pytest.fixture
def context():
    return zmq.Context.instance()

@pytest.fixture
def logger():
    return Mock(spec=loggers.Logger)

@pytest.fixture
def interface(context, logger):
    intf = SupvisorsZmqEventInterface(context, 7777, logger)
    yield intf
    intf.subscriber.close()

def test_creation(context, logger, interface):
    """ Test the initialization of the SupvisorsEventInterface. """
    assert isinstance(interface, threading.Thread)
    assert interface.zmq_context is context
    assert interface.event_port == 7777
    assert interface.logger is logger
    assert isinstance(interface.subscriber, EventSubscriber)
    assert isinstance(interface.stop_event, threading.Event)

def test_stop(interface):
    """ Test the SupvisorsEventInterface.stop method. """
    assert not interface.stop_event.is_set()
    interface.stop()
    assert interface.stop_event.is_set()

def test_run_nothing(mocker, context, logger, interface):
    """ Test the behavior of the thread loop when nothing to poll. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    logger.reset_mock()
    # test run method when nothing to poll
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop')]
    assert not logger.debug.called
    assert not logger.error.called
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed

def test_run_no_pollin(mocker, context, logger, interface):
    """ Test the behavior of the thread loop when nothing to poll in. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    mocker.patch('zmq.Poller.poll', return_value={interface.subscriber.socket: zmq.POLLOUT})
    logger.reset_mock()
    # test run method when nothing to poll
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop')]
    assert not logger.debug.called
    assert not logger.error.called
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed

def test_run_receive_error(mocker, context, logger, interface):
    """ Test the behavior of the thread loop with exception on receive. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    mocker.patch('zmq.Poller.poll', return_value={interface.subscriber.socket: zmq.POLLIN})
    mocker.patch.object(interface.subscriber, 'receive', side_effect=ZMQError(10, 'failed'))
    logger.reset_mock()
    # test run method with exception on receive
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop')]
    assert logger.debug.call_args_list == [call('SupvisorsEventInterface.run: got message on subscriber')]
    assert logger.error.call_args_list == [call('SupvisorsEventInterface.run: failed to get data from subscriber:'
                                                ' failed')]
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed

def test_run_receive_unexpected_event(mocker, context, logger, interface):
    """ Test the behavior of the thread loop with Supvisors status message. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    mocker.patch('zmq.Poller.poll', return_value={interface.subscriber.socket: zmq.POLLIN})
    mocker.patch.object(interface.subscriber, 'receive',
                        return_value=('unexpected', 'supvisors payload'))
    logger.reset_mock()
    # test run method with Supvisors status message
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop')]
    assert logger.debug.call_args_list == [call('SupvisorsEventInterface.run: got message on subscriber')]
    assert logger.error.call_args_list == [call('SupvisorsEventInterface.run: unexpected event type unexpected')]
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed

def test_run_receive_supvisors(mocker, context, logger, interface):
    """ Test the behavior of the thread loop with Supvisors status message. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    mocker.patch('zmq.Poller.poll', return_value={interface.subscriber.socket: zmq.POLLIN})
    mocker.patch.object(interface.subscriber, 'receive',
                        return_value=(EventHeaders.SUPVISORS.value, 'supvisors payload'))
    logger.reset_mock()
    # test run method with Supvisors status message
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop'),
                                          call('SupvisorsEventInterface.on_supvisors_status:'
                                               ' got Supvisors Status message: supvisors payload')]
    assert logger.debug.call_args_list == [call('SupvisorsEventInterface.run: got message on subscriber')]
    assert not logger.error.called
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed

def test_run_receive_instance(mocker, context, logger, interface):
    """ Test the behavior of the thread loop with Instance status message. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    mocker.patch('zmq.Poller.poll', return_value={interface.subscriber.socket: zmq.POLLIN})
    mocker.patch.object(interface.subscriber, 'receive',
                        return_value=(EventHeaders.INSTANCE.value, 'instance payload'))
    logger.reset_mock()
    # test run method with Instance status message
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop'),
                                          call('SupvisorsEventInterface.on_instance_status:'
                                               ' got Instance Status message: instance payload')]
    assert logger.debug.call_args_list == [call('SupvisorsEventInterface.run: got message on subscriber')]
    assert not logger.error.called
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed

def test_run_receive_application(mocker, context, logger, interface):
    """ Test the behavior of the thread loop with Application status message. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    mocker.patch('zmq.Poller.poll', return_value={interface.subscriber.socket: zmq.POLLIN})
    mocker.patch.object(interface.subscriber, 'receive',
                        return_value=(EventHeaders.APPLICATION.value, 'application payload'))
    logger.reset_mock()
    # test run method with Application status message
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop'),
                                          call('SupvisorsEventInterface.on_application_status:'
                                               ' got Application Status message: application payload')]
    assert logger.debug.call_args_list == [call('SupvisorsEventInterface.run: got message on subscriber')]
    assert not logger.error.called
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed

def test_run_receive_process(mocker, context, logger, interface):
    """ Test the behavior of the thread loop with Process status message. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    mocker.patch('zmq.Poller.poll', return_value={interface.subscriber.socket: zmq.POLLIN})
    mocker.patch.object(interface.subscriber, 'receive',
                        return_value=(EventHeaders.PROCESS_STATUS.value, 'process payload'))
    logger.reset_mock()
    # test run method with Process status message
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop'),
                                          call('SupvisorsEventInterface.on_process_status:'
                                               ' got Process Status message: process payload')]
    assert logger.debug.call_args_list == [call('SupvisorsEventInterface.run: got message on subscriber')]
    assert not logger.error.called
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed

def test_run_receive_event(mocker, context, logger, interface):
    """ Test the behavior of the thread loop with Process event message. """
    # patch the context
    mocker.patch.object(interface.stop_event, 'is_set', side_effect=[False, True])
    mocker.patch('zmq.Poller.poll', return_value={interface.subscriber.socket: zmq.POLLIN})
    mocker.patch.object(interface.subscriber, 'receive',
                        return_value=(EventHeaders.PROCESS_EVENT.value, 'event payload'))
    logger.reset_mock()
    # test run method with Process event message
    interface.run()
    assert logger.info.call_args_list == [call('SupvisorsEventInterface.run: entering main loop'),
                                          call('SupvisorsEventInterface.on_process_event:'
                                               ' got Process Event message: event payload')]
    assert logger.debug.call_args_list == [call('SupvisorsEventInterface.run: got message on subscriber')]
    assert not logger.error.called
    assert logger.warn.call_args_list == [call('SupvisorsEventInterface.run: exiting main loop')]
    assert interface.subscriber.socket.closed


text:
package org.apache.spark.ml.feature

import org.apache.spark.ml.param.ParamsSuite
import org.scalatest.exceptions.TestFailedException

import org.apache.spark.SparkFunSuite
import org.apache.spark.mllib.linalg.{DenseVector, SparseVector, Vector, Vectors}
import org.apache.spark.mllib.util.MLlibTestSparkContext
import org.apache.spark.mllib.util.TestingUtils._
import org.apache.spark.sql.Row

class PolynomialExpansionSuite extends SparkFunSuite with MLlibTestSparkContext {

  test("params") {
    ParamsSuite.checkParams(new PolynomialExpansion)
  }

  test("Polynomial expansion with default parameter") {
    val data = Array(
      Vectors.sparse(3, Seq((0, -2.0), (1, 2.3))),
      Vectors.dense(-2.0, 2.3),
      Vectors.dense(0.0, 0.0, 0.0),
      Vectors.dense(0.6, -1.1, -3.0),
      Vectors.sparse(3, Seq())
    )

    val twoDegreeExpansion: Array[Vector] = Array(
      Vectors.sparse(9, Array(0, 1, 2, 3, 4), Array(-2.0, 4.0, 2.3, -4.6, 5.29)),
      Vectors.dense(-2.0, 4.0, 2.3, -4.6, 5.29),
      Vectors.dense(new Array[Double](9)),
      Vectors.dense(0.6, 0.36, -1.1, -0.66, 1.21, -3.0, -1.8, 3.3, 9.0),
      Vectors.sparse(9, Array.empty, Array.empty))

    val df = sqlContext.createDataFrame(data.zip(twoDegreeExpansion)).toDF("features", "expected")

    val polynomialExpansion = new PolynomialExpansion()
      .setInputCol("features")
      .setOutputCol("polyFeatures")

    polynomialExpansion.transform(df).select("polyFeatures", "expected").collect().foreach {
      case Row(expanded: DenseVector, expected: DenseVector) =>
        assert(expanded ~== expected absTol 1e-1)
      case Row(expanded: SparseVector, expected: SparseVector) =>
        assert(expanded ~== expected absTol 1e-1)
      case _ =>
        throw new TestFailedException("Unmatched data types after polynomial expansion", 0)
    }
  }

  test("Polynomial expansion with setter") {
    val data = Array(
      Vectors.sparse(3, Seq((0, -2.0), (1, 2.3))),
      Vectors.dense(-2.0, 2.3),
      Vectors.dense(0.0, 0.0, 0.0),
      Vectors.dense(0.6, -1.1, -3.0),
      Vectors.sparse(3, Seq())
    )

    val threeDegreeExpansion: Array[Vector] = Array(
      Vectors.sparse(19, Array(0, 1, 2, 3, 4, 5, 6, 7, 8),
        Array(-2.0, 4.0, -8.0, 2.3, -4.6, 9.2, 5.29, -10.58, 12.17)),
      Vectors.dense(-2.0, 4.0, -8.0, 2.3, -4.6, 9.2, 5.29, -10.58, 12.17),
      Vectors.dense(new Array[Double](19)),
      Vectors.dense(0.6, 0.36, 0.216, -1.1, -0.66, -0.396, 1.21, 0.726, -1.331, -3.0, -1.8,
        -1.08, 3.3, 1.98, -3.63, 9.0, 5.4, -9.9, -27.0),
      Vectors.sparse(19, Array.empty, Array.empty))

    val df = sqlContext.createDataFrame(data.zip(threeDegreeExpansion)).toDF("features", "expected")

    val polynomialExpansion = new PolynomialExpansion()
      .setInputCol("features")
      .setOutputCol("polyFeatures")
      .setDegree(3)

    polynomialExpansion.transform(df).select("polyFeatures", "expected").collect().foreach {
      case Row(expanded: DenseVector, expected: DenseVector) =>
        assert(expanded ~== expected absTol 1e-1)
      case Row(expanded: SparseVector, expected: SparseVector) =>
        assert(expanded ~== expected absTol 1e-1)
      case _ =>
        throw new TestFailedException("Unmatched data types after polynomial expansion", 0)
    }
  }
}