Merge lp:~mvngu/igraph/game-junk into lp:~igraph/igraph/0.6-main-old

Proposed by Minh Van Nguyen
Status: Merged
Merged at revision: 2493
Proposed branch: lp:~mvngu/igraph/game-junk
Merge into: lp:~igraph/igraph/0.6-main-old
Diff against target: 500 lines (+317/-55)
7 files modified
.bzrignore (+1/-0)
examples/simple/igraph_random_sample.c (+183/-0)
src/iterators.c (+62/-36)
src/random.c (+37/-10)
src/structure_generators.c (+11/-5)
src/type_indexededgelist.c (+18/-4)
tests/other.at (+5/-0)
To merge this branch: bzr merge lp:~mvngu/igraph/game-junk
Reviewer Review Type Date Requested Status
Gábor Csárdi Approve
Review via email: mp+61887@code.launchpad.net

Description of the change

A bunch of documentation fixes. In particular:

* Where possible, clearly document possible values that an argument would accept.

* Clarify the concept of selector and iterator for vertices (and edges).

* Proper citation of the paper (Vitter 1987) for the algorithm on random sampling.

* In the function for random sampling using the algorithm in (Vitter 1987), handle some corner cases that would cause that function to hang indefinitely.

To post a comment you must log in.
lp:~mvngu/igraph/game-junk updated
2485. By Tamás Nepusz

Python: sorted out Graph.assortativity() properly

Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

Thanks! This seems mostly fine, except, that I think the Vitter algorithm is supposed to work when l=h. If I remember well.

lp:~mvngu/igraph/game-junk updated
2486. By Gábor Csárdi

Clarify the concepts of vertex (edge) selector and iterator.

2487. By Gábor Csárdi

Clarify the documentation of igraph_vs_adj().

2488. By Gábor Csárdi

Clarify documentation of igraph_vs_nonadj().

2489. By Gábor Csárdi

Clarify documentation of igraph_small().

2490. By Gábor Csárdi

Clarify documentation of igraph_empty().

2491. By Gábor Csárdi

Clarify documentation of igraph_empty_attrs().

2492. By Gábor Csárdi

Proper citation of (Vitter 1987) for algorithm for random sampling.

2493. By Gábor Csárdi

Handle boundary cases for random sampling with algorithm in (Vitter 1987).

Revision history for this message
Gábor Csárdi (gabor.csardi) wrote :

OK, I merged everything, after some minor changes.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-05-17 16:30:25 +0000
3+++ .bzrignore 2011-05-22 08:26:01 +0000
4@@ -255,6 +255,7 @@
5 examples/simple/igraph_preference_game.c.xml
6 examples/simple/igraph_psumtree.c.xml
7 examples/simple/igraph_radius.c.xml
8+examples/simple/igraph_random_sample.c.xml
9 examples/simple/igraph_read_graph_dl.c.xml
10 examples/simple/igraph_read_graph_graphdb.c.xml
11 examples/simple/igraph_read_graph_lgl.c.xml
12
13=== added file 'examples/simple/igraph_random_sample.c'
14--- examples/simple/igraph_random_sample.c 1970-01-01 00:00:00 +0000
15+++ examples/simple/igraph_random_sample.c 2011-05-22 08:26:01 +0000
16@@ -0,0 +1,183 @@
17+/* -*- mode: C -*- */
18+/*
19+ Test suite for random sampling.
20+ Copyright (C) 2011 Minh Van Nguyen <nguyenminh2@gmail.com>
21+
22+ This program is free software; you can redistribute it and/or modify
23+ it under the terms of the GNU General Public License as published by
24+ the Free Software Foundation; either version 2 of the License, or
25+ (at your option) any later version.
26+
27+ This program is distributed in the hope that it will be useful,
28+ but WITHOUT ANY WARRANTY; without even the implied warranty of
29+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30+ GNU General Public License for more details.
31+
32+ You should have received a copy of the GNU General Public License
33+ along with this program; if not, write to the Free Software
34+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35+ 02110-1301 USA
36+*/
37+
38+#include <assert.h>
39+#include <igraph.h>
40+#include <math.h>
41+#include <stdio.h>
42+#include <time.h>
43+
44+#define R_INTEGER(a,b) (igraph_rng_get_integer(&igraph_rng_default, (a), (b)))
45+
46+/* test parameters */
47+typedef struct {
48+ igraph_integer_t low;
49+ igraph_integer_t high;
50+ igraph_integer_t length;
51+ int retval;
52+} sampling_test_t;
53+
54+/* Error tests. Don't be afraid to crash the library function.
55+ */
56+int error_test() {
57+ const igraph_integer_t min = -1000;
58+ const igraph_integer_t max = 1000;
59+ igraph_integer_t low; /* lower limit */
60+ igraph_integer_t high; /* upper limit */
61+ igraph_integer_t length; /* sample size */
62+ igraph_integer_t poolsize; /* size of candidate pool */
63+ igraph_vector_t V;
64+ int i, n, ret;
65+ sampling_test_t *test;
66+
67+ igraph_rng_seed(&igraph_rng_default, time(0));
68+ igraph_vector_init(&V, /*size*/ 0);
69+
70+ /* test parameters */
71+ /*----------low----high----length----retval----------*/
72+ /* lower limit is greater than upper limit */
73+ do {
74+ high = (igraph_integer_t)R_INTEGER(min, max);
75+ } while (high == max);
76+ do {
77+ low = (igraph_integer_t)R_INTEGER(min, max);
78+ } while (low <= high);
79+ assert(low > high);
80+ length = (igraph_integer_t)R_INTEGER(min, max);
81+ sampling_test_t lower_bigger = {low, high, length, IGRAPH_EINVAL};
82+ /* lower limit equals upper limit */
83+ high = (igraph_integer_t)R_INTEGER(min, max);
84+ low = high;
85+ length = (igraph_integer_t)R_INTEGER(min, max);
86+ sampling_test_t low_is_high = {low, high, length, IGRAPH_EINVAL};
87+ /* sample size is greater than size of candidate pool */
88+ do {
89+ high = (igraph_integer_t)R_INTEGER(min, max);
90+ } while (high == min);
91+ do {
92+ low = (igraph_integer_t)R_INTEGER(min, max);
93+ } while (low >= high);
94+ assert(low < high);
95+ poolsize = (igraph_integer_t)fabs((double)high - (double)low);
96+ length = poolsize * poolsize;
97+ sampling_test_t sample_size_bigger = {low, high, length, IGRAPH_EINVAL};
98+
99+ sampling_test_t *all_checks[] = {/* 1 */ &lower_bigger,
100+ /* 2 */ &low_is_high,
101+ /* 3 */ &sample_size_bigger};
102+
103+ /* failure is the mother of success */
104+ igraph_set_error_handler(igraph_error_handler_ignore);
105+ n = 3;
106+ for (i = 0; i < n; i++) {
107+ test = all_checks[i];
108+ ret = igraph_random_sample(&V, test->low, test->high, test->length);
109+ if (ret != test->retval) {
110+ printf("Error test no. %d failed.\n", (int)(i + 1));
111+ return IGRAPH_FAILURE;
112+ }
113+ }
114+
115+ igraph_vector_destroy(&V);
116+
117+ return IGRAPH_SUCCESS;
118+}
119+
120+/* Get a few random samples and test their properties.
121+ */
122+int random_sample_test() {
123+ const igraph_integer_t min = -1000;
124+ const igraph_integer_t max = 1000;
125+ igraph_integer_t low; /* lower limit */
126+ igraph_integer_t high; /* upper limit */
127+ igraph_integer_t length; /* sample size */
128+ igraph_integer_t poolsize; /* size of candidate pool */
129+ igraph_real_t sP; /* population total sum */
130+ igraph_real_t ss; /* sample total sum */
131+ igraph_vector_t V;
132+ int i;
133+
134+ igraph_rng_seed(&igraph_rng_default, time(0));
135+
136+ /* The generated sequence of numbers must be in increasing order. */
137+ igraph_vector_init(&V, /*size*/ 0);
138+ do {
139+ high = (igraph_integer_t)R_INTEGER(min, max);
140+ } while (high == min);
141+ do {
142+ low = (igraph_integer_t)R_INTEGER(min, max);
143+ } while (low >= high);
144+ poolsize = (igraph_integer_t)fabs((double)high - (double)low);
145+ do {
146+ length = (igraph_integer_t)R_INTEGER(1, max);
147+ } while (length > poolsize);
148+ igraph_random_sample(&V, low, high, length);
149+ if (length != igraph_vector_size(&V)) {
150+ printf("Requested vector length and resulting length mismatch.\n");
151+ return IGRAPH_FAILURE;
152+ }
153+ for (i = 0; i < length - 1; i++) {
154+ if (VECTOR(V)[i] >= VECTOR(V)[i+1]) {
155+ printf("Sample not in increasing order.\n");
156+ return IGRAPH_FAILURE;
157+ }
158+ }
159+ igraph_vector_destroy(&V);
160+
161+ /* Let P be a candidate pool of positive integers with total sum s_P. */
162+ /* Let S be a random sample from P and having total sum s_S. Then we */
163+ /* have the bound s_s <= s_P. */
164+ igraph_vector_init(&V, /*size*/ 0);
165+ low = 1;
166+ do {
167+ high = (igraph_integer_t)R_INTEGER(low, max);
168+ } while (high == low);
169+ poolsize = (igraph_integer_t)fabs((double)high - (double)low);
170+ do {
171+ length = (igraph_integer_t)R_INTEGER(low, max);
172+ } while (length > poolsize);
173+ igraph_random_sample(&V, low, high, length);
174+ /* Use Gauss' formula to sum all consecutive positive integers from 1 */
175+ /* up to and including an upper limit. In LaTeX, Gauss' formula is */
176+ /* \sum_{i=1}^n i = \frac{n(n+1)}{2} where n is the upper limit. */
177+ sP = (high * (high + 1)) / 2;
178+ ss = igraph_vector_sum(&V);
179+ if (ss > sP) {
180+ printf("Sum of sampled sequence exceeds sum of whole population.\n");
181+ return IGRAPH_FAILURE;
182+ }
183+ igraph_vector_destroy(&V);
184+
185+ return IGRAPH_SUCCESS;
186+}
187+
188+int main() {
189+ int ret;
190+
191+ ret = error_test();
192+ if (ret)
193+ return IGRAPH_FAILURE;
194+ ret = random_sample_test();
195+ if (ret)
196+ return IGRAPH_FAILURE;
197+
198+ return IGRAPH_SUCCESS;
199+}
200
201=== modified file 'src/iterators.c'
202--- src/iterators.c 2011-03-01 20:27:49 +0000
203+++ src/iterators.c 2011-05-22 08:26:01 +0000
204@@ -41,23 +41,33 @@
205 * independently of the graph.</para>
206 *
207 * <para>While this might sound quite mysterious, it is actually very
208- * simple. For example all vertices of a graph can be selected by
209- * \ref igraph_vs_all(), and the graph independence means that
210- * \ref igraph_vs_all() is not parametrized by a graph object. Ie.
211- * \ref igraph_vs_all() is the \em concept of selecting all vertices
212- * of a graph.</para>
213- *
214- * <para>This means that for determining the actual vertex id's implied
215- * by a vertex selector it needs to be instantiated with a graph
216- * object, the instantiation results a vertex iterator.</para>
217- *
218- * <para>Some vertex selectors have \em immediate versions, these have
219- * prefix <code>igraph_vss</code> instead of <code>igraph_vs</code>, eg.
220- * \ref igraph_vss_all() instead of \ref igraph_vs_all().
221- * These immediate versions are to be used in the parameter list of the igraph
222- * functions, like \ref igraph_degree(). These functions are not
223- * associated with any \type igraph_vs_t object, so they have no
224- * separate constructors and destructors (destroy functions).</para>
225+ * simple. For example, all vertices of a graph can be selected by
226+ * \ref igraph_vs_all() and the graph independence means that
227+ * \ref igraph_vs_all() is not parametrized by a graph object. That is,
228+ * \ref igraph_vs_all() is the general \em concept of selecting all vertices
229+ * of a graph. A vertex selector is then a way to specify the class of vertices
230+ * to be visited. The selector might specify that all vertices of a graph or
231+ * all the neighbours of a vertex are to be visited. A vertex selector is a
232+ * way of saying that you want to visit a bunch of vertices, as opposed to a
233+ * vertex iterator which is a concrete plan for visiting each of the
234+ * chosen vertices of a specific graph.</para>
235+ *
236+ * <para>To determine the actual vertex IDs implied by a vertex selector, you
237+ * need to apply the concept of selecting vertices to a specific graph object.
238+ * This can be accomplished by instantiating a vertex iterator using a
239+ * specific vertex selection concept and a specific graph object. The notion
240+ * of vertex iterators can be thought of in the following way. Given a
241+ * specific graph object and the class of vertices to be visited, a vertex
242+ * iterator is a road map, plan or route for how to visit the chosen
243+ * vertices.</para>
244+ *
245+ * <para>Some vertex selectors have \em immediate versions. These have the
246+ * prefix \c igraph_vss instead of \c igraph_vs, e.g. \ref igraph_vss_all()
247+ * instead of \ref igraph_vs_all(). The immediate versions are to be used in
248+ * the parameter list of the igraph functions, such as \ref igraph_degree().
249+ * These functions are not associated with any \type igraph_vs_t object, so
250+ * they have no separate constructors and destructors
251+ * (destroy functions).</para>
252 */
253
254 /**
255@@ -115,19 +125,25 @@
256 * All neighboring vertices of a given vertex are selected by this
257 * selector. The \c mode argument controls the type of the neighboring
258 * vertices to be selected. The vertices are visited in increasing vertex
259- * id order, as of igraph version 0.4.
260+ * ID order, as of igraph version 0.4.
261 *
262 * \param vs Pointer to an uninitialized vertex selector object.
263- * \param vid Vertex id, the center of the neighborhood.
264+ * \param vid Vertex ID, the center of the neighborhood.
265 * \param mode Decides the type of the neighborhood for directed
266- * graphs. Possible values:
267- * \c IGRAPH_OUT, all vertices to which there is a directed edge
268- * from \c vid.
269- * \c IGRAPH_IN, all vertices from which there is a directed
270- * edge from \c vid.
271- * \c IGRAPH_ALL, all vertices to which or from which there is
272- * a directed edge from/to \c vid.
273- * This parameter is ignored for undirected graphs.
274+ * graphs. This parameter is ignored for undirected graphs.
275+ * Possible values:
276+ * \clist
277+ * \cli IGRAPH_OUT
278+ * All vertices to which there is a directed edge from \c vid. That
279+ * is, all the out-neighbors of \c vid.
280+ * \cli IGRAPH_IN
281+ * All vertices from which there is a directed edge to \c vid. In
282+ * other words, all the in-neighbors of \c vid.
283+ * \cli IGRAPH_ALL
284+ * All vertices to which or from which there is a directed edge
285+ * from/to \c vid. That is, all the neighbors of \c vid considered
286+ * as if the graph is undirected.
287+ * \endclist
288 * \return Error code.
289 *
290 * Time complexity: O(1).
291@@ -147,19 +163,29 @@
292 *
293 * All non-neighboring vertices of a given vertex. The \p mode
294 * argument controls the type of neighboring vertices \em not to
295- * select.
296+ * select. Instead of selecting immediate neighbors of \c vid as is done by
297+ * \ref igraph_vs_adj(), the current function selects vertices that are \em not
298+ * immediate neighbors of \c vid.
299+ *
300 * \param vs Pointer to an uninitialized vertex selector object.
301- * \param vid Vertex id, the \quote center \endquote of the
302+ * \param vid Vertex ID, the \quote center \endquote of the
303 * non-neighborhood.
304 * \param mode The type of neighborhood not to select in directed
305 * graphs. Possible values:
306- * \c IGRAPH_OUT, all vertices will be selected except those to
307- * which there is a directed edge from \p vid.
308- * \c IGRAPH_IN, all vertices will be selected except those
309- * from which there is a directed edge to \p vid.
310- * \c IGRAPH_ALL, all vertices will be selected except those
311- * from or to which there is a directed edge to or from \p
312- * vid.
313+ * \clist
314+ * \cli IGRAPH_OUT
315+ * All vertices will be selected except those to which there is a
316+ * directed edge from \c vid. That is, we select all vertices
317+ * excluding the out-neighbors of \c vid.
318+ * \cli IGRAPH_IN
319+ * All vertices will be selected except those from which there is a
320+ * directed edge to \c vid. In other words, we select all vertices
321+ * but the in-neighbors of \c vid.
322+ * \cli IGRAPH_ALL
323+ * All vertices will be selected except those from or to which there
324+ * is a directed edge to or from \c vid. That is, we select all
325+ * vertices of \c vid except for its immediate neighbors.
326+ * \endclist
327 * \return Error code.
328 *
329 * Time complexity: O(1).
330
331=== modified file 'src/random.c'
332--- src/random.c 2011-05-09 17:54:01 +0000
333+++ src/random.c 2011-05-22 08:26:01 +0000
334@@ -948,27 +948,44 @@
335 * </para><para>
336 * This function generates an increasing sequence of random integer
337 * numbers from a given interval. The algorithm is taken literally
338- * from Jeffrey Scott Vitter: 'An Efficient Algorithm for Sequential
339- * Random Sampling', ACM Transactions on Mathematical Software, 13/1,
340- * 58--67. This method can be used for generating numbers from a
341- * \em very large interval, it is primarily created for randomly
342+ * from (Vitter 1987). This method can be used for generating numbers from a
343+ * \em very large interval. It is primarily created for randomly
344 * selecting some edges from the sometimes huge set of possible edges
345 * in a large graph.
346- * \param res Pointer to an initialized vector, this will hold the
347+ * \param res Pointer to an initialized vector. This will hold the
348 * result. It will be resized to the proper size.
349- * \param l The lower limit of the generation interval (inclusive).
350- * \param h The upper limit of the generation interval (inclusive).
351+ * \param l The lower limit of the generation interval (inclusive). This must
352+ * be less than the upper limit.
353+ * \param h The upper limit of the generation interval (inclusive). This must
354+ * be greater than the lower limit.
355 * \param length The number of random integers to generate.
356- * \return Error code.
357+ * \return The error code \c IGRAPH_EINVAL is returned in each of the
358+ * following cases: (1) The given lower limit is greater than the
359+ * given upper limit, i.e. \c l &gt; \c h. (2) The lower limit is
360+ * equal to the upper limit, i.e. \c l = \c h. (3) Assumming that
361+ * \c l &lt; \c h and N is the sample size, the above error code is
362+ * returned if N &gt; |\c h - \c l|, i.e. the sample size exceeds the
363+ * size of the candidate pool.
364 *
365- * Time complexity: according to the referenced paper, the expected
366+ * Time complexity: according to (Vitter 1987), the expected
367 * running time is O(length).
368+ *
369+ * </para><para>
370+ * Reference:
371+ * \clist
372+ * \cli (Vitter 1987)
373+ * J. S. Vitter. An efficient algorithm for sequential random sampling.
374+ * \emb ACM Transactions on Mathematical Software, \eme 13(1):58--67, 1987.
375+ * \endclist
376+ *
377+ * \example examples/simple/igraph_random_sample.c
378 */
379
380 int igraph_random_sample(igraph_vector_t *res, igraph_integer_t l, igraph_integer_t h,
381 igraph_integer_t length) {
382 igraph_real_t N=h-l+1;
383 igraph_real_t n=length;
384+ igraph_integer_t poolsize; /* size of candidate pool */
385 int retval;
386
387 igraph_real_t nreal=length;
388@@ -980,7 +997,17 @@
389 igraph_real_t negalphainv=-13;
390 igraph_real_t threshold=-negalphainv*n;
391 igraph_real_t S;
392-
393+
394+ /* getting back some sense of sanity */
395+ if (l > h)
396+ IGRAPH_ERROR("Lower limit is greater than upper limit", IGRAPH_EINVAL);
397+ if (l == h)
398+ IGRAPH_ERROR("Lower limit equals upper limit", IGRAPH_EINVAL);
399+ /* now we know that l < h */
400+ poolsize = (igraph_integer_t)fabs((double)h - (double)l);
401+ if (length > poolsize)
402+ IGRAPH_ERROR("Sample size exceeds size of candidate pool", IGRAPH_EINVAL);
403+
404 igraph_vector_clear(res);
405 IGRAPH_CHECK(igraph_vector_reserve(res, length));
406
407
408=== modified file 'src/structure_generators.c'
409--- src/structure_generators.c 2011-05-16 11:23:07 +0000
410+++ src/structure_generators.c 2011-05-22 08:26:01 +0000
411@@ -1028,7 +1028,7 @@
412
413 /**
414 * \function igraph_small
415- * \brief Shorthand to create a short graph, giving the edges as arguments
416+ * \brief Shorthand to create a short graph, giving the edges as arguments.
417 *
418 * </para><para>
419 * This function is handy when a relatively small graph needs to be created.
420@@ -1040,11 +1040,17 @@
421 * the highest value of the 'int' type can be created this way. If you
422 * give larger values then the result is undefined.
423 *
424- * \param graph Pointer to an uninitialized graph object, the result
425+ * \param graph Pointer to an uninitialized graph object. The result
426 * will be stored here.
427- * \param n The number of vertices in the graph, an integer.
428- * \param directed Logical constant, gives whether the graph should be
429- * directed.
430+ * \param n The number of vertices in the graph; a nonnegative integer.
431+ * \param directed Logical constant; gives whether the graph should be
432+ * directed. Supported values are:
433+ * \clist
434+ * \cli IGRAPH_DIRECTED
435+ * The graph to be created will be \em directed.
436+ * \cli IGRAPH_UNDIRECTED
437+ * The graph to be created will be \em undirected.
438+ * \endclist
439 * \param ... The additional arguments giving the edges of the
440 * graph. Don't forget to supply an additional '-1' after the last
441 * (meaningful) argument.
442
443=== modified file 'src/type_indexededgelist.c'
444--- src/type_indexededgelist.c 2011-05-05 10:25:07 +0000
445+++ src/type_indexededgelist.c 2011-05-22 08:26:01 +0000
446@@ -61,7 +61,14 @@
447 * \param graph Pointer to a not-yet initialized graph object.
448 * \param n The number of vertices in the graph, a non-negative
449 * integer number is expected.
450- * \param directed Whether the graph is directed or not.
451+ * \param directed Boolean; whether the graph is directed or not. Supported
452+ * values are:
453+ * \clist
454+ * \cli IGRAPH_DIRECTED
455+ * The graph will be \em directed.
456+ * \cli IGRAPH_UNDIRECTED
457+ * The graph will be \em undirected.
458+ * \endclist
459 * \return Error code:
460 * \c IGRAPH_EINVAL: invalid number of vertices.
461 *
462@@ -83,12 +90,19 @@
463 * </para><para>
464 * Use this instead of \ref igraph_empty() if you wish to add some graph
465 * attributes right after initialization. This function is currently
466- * not very interesting for the ordinary user, just supply 0 here or
467+ * not very interesting for the ordinary user. Just supply 0 here or
468 * use \ref igraph_empty().
469 * \param graph Pointer to a not-yet initialized graph object.
470- * \param n The number of vertices in the graph, a non-negative
471+ * \param n The number of vertices in the graph; a non-negative
472 * integer number is expected.
473- * \param directed Whether the graph is directed or not.
474+ * \param directed Boolean; whether the graph is directed or not. Supported
475+ * values are:
476+ * \clist
477+ * \cli IGRAPH_DIRECTED
478+ * Create a \em directed graph.
479+ * \cli IGRAPH_UNDIRECTED
480+ * Create an \em undirected graph.
481+ * \endclist
482 * \param attr The attributes.
483 * \return Error code:
484 * \c IGRAPH_EINVAL: invalid number of vertices.
485
486=== modified file 'tests/other.at'
487--- tests/other.at 2011-05-09 17:54:01 +0000
488+++ tests/other.at 2011-05-22 08:26:01 +0000
489@@ -36,6 +36,11 @@
490 AT_COMPILE_CHECK([simple/mt.c])
491 AT_CLEANUP
492
493+AT_SETUP([Random sampling from consecutive sequence:])
494+AT_KEYWORDS([random sampling])
495+AT_COMPILE_CHECK([simple/igraph_random_sample.c])
496+AT_CLEANUP
497+
498 AT_SETUP([Fisher-Yates shuffle:])
499 AT_KEYWORDS([Fisher-Yates shuffle random permutation])
500 AT_COMPILE_CHECK([simple/igraph_fisher_yates_shuffle.c])

Subscribers

People subscribed via source and target branches