GNUnet  0.11.x
Macros | Functions
rps-test_util.h File Reference

Some utils facilitating the view into the internals for the sampler needed for evaluation. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define TO_FILE   0
 
#define to_file(file_name, ...)
 This function is used to facilitate writing important information to disk. More...
 
#define to_file_w_len(file_name, len, ...)
 

Functions

char * auth_key_to_string (struct GNUNET_CRYPTO_AuthKey auth_key)
 
struct GNUNET_CRYPTO_AuthKey string_to_auth_key (const char *str)
 
struct GNUNET_DISK_FileHandleget_file_handle (const char *name)
 Get file handle. More...
 
int close_all_files ()
 Close all files that were opened with get_file_handle. More...
 
char * store_prefix_file_name (const unsigned int index, const char *prefix)
 
void to_file_raw (const char *file_name, const char *buf, size_t size_buf)
 
void to_file_raw_unaligned (const char *file_name, const char *buf, size_t size_buf, unsigned bits_needed)
 
uint32_t fac (uint32_t x)
 Factorial. More...
 
uint32_t binom (uint32_t n, uint32_t k)
 Binomial coefficient (n choose k) More...
 

Detailed Description

Some utils facilitating the view into the internals for the sampler needed for evaluation.

Author
Julius B√ľnger

Definition in file rps-test_util.h.

Macro Definition Documentation

◆ TO_FILE

#define TO_FILE   0

Definition at line 31 of file rps-test_util.h.

◆ to_file

#define to_file (   file_name,
  ... 
)
Value:
do { \
char tmp_buf[512] = ""; \
int size; \
if (NULL == file_name) break; \
size = GNUNET_snprintf (tmp_buf, sizeof(tmp_buf), __VA_ARGS__); \
if (0 > size) \
{ \
"Failed to create tmp_buf\n"); \
break; \
} \
(void) strncat (tmp_buf, "\n", 511); \
GNUNET_DISK_file_write (get_file_handle (file_name), \
tmp_buf, \
strnlen (tmp_buf, 512)); \
} while (0);
static char * file_name
Dump file name.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
struct GNUNET_DISK_FileHandle * get_file_handle(const char *name)
Get file handle.
Definition: rps-test_util.c:74
static unsigned int size
Size of the "table".
Definition: peer.c:67
static size_t strnlen(const char *s, size_t n)

This function is used to facilitate writing important information to disk.

Definition at line 65 of file rps-test_util.h.

Referenced by do_round(), hist_update(), insert_in_sampler(), stat_iterator(), view_update_cb(), and write_final_stats().

◆ to_file_w_len

#define to_file_w_len (   file_name,
  len,
  ... 
)
Value:
do { char tmp_buf [len]; \
int size; \
memset (tmp_buf, 0, len); \
size = GNUNET_snprintf (tmp_buf, \
sizeof( \
tmp_buf), \
__VA_ARGS__); \
if (0 > size) \
{ \
GNUNET_log ( \
"Failed to create tmp_buf\n"); \
break; \
} \
(void) strncat (tmp_buf, "\n", 2); \
GNUNET_DISK_file_write ( \
tmp_buf, \
strnlen ( \
tmp_buf, len)); \
} while (0);
static char * file_name
Dump file name.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
struct GNUNET_DISK_FileHandle * get_file_handle(const char *name)
Get file handle.
Definition: rps-test_util.c:74
static unsigned int size
Size of the "table".
Definition: peer.c:67
static size_t strnlen(const char *s, size_t n)
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...

Definition at line 83 of file rps-test_util.h.

Referenced by compute_probabilities().

Function Documentation

◆ auth_key_to_string()

char* auth_key_to_string ( struct GNUNET_CRYPTO_AuthKey  auth_key)

Definition at line 380 of file rps-test_util.c.

References buf, end, GNUNET_break, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_malloc, GNUNET_snprintf(), GNUNET_STRINGS_data_to_string(), GNUNET_CRYPTO_AuthKey::key, LOG, and size.

381 {
382  int size;
383  size_t name_buf_size;
384  char *end;
385  char *buf;
386  char *name_buf;
387  size_t keylen = (sizeof(struct GNUNET_CRYPTO_AuthKey)) * 8;
388 
389  name_buf_size = 512 * sizeof(char);
390  name_buf = GNUNET_malloc (name_buf_size);
391 
392  if (keylen % 5 > 0)
393  keylen += 5 - keylen % 5;
394  keylen /= 5;
395  buf = GNUNET_malloc (keylen + 1);
396 
397  end = GNUNET_STRINGS_data_to_string (&(auth_key.key),
398  sizeof(struct GNUNET_CRYPTO_AuthKey),
399  buf,
400  keylen);
401 
402  if (NULL == end)
403  {
404  GNUNET_free (buf);
405  GNUNET_break (0);
406  }
407  else
408  {
409  *end = '\0';
410  }
411 
412  size = GNUNET_snprintf (name_buf, name_buf_size, "sampler_el-%s", buf);
413  if (0 > size)
414  LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to create name_buf\n");
415 
416  GNUNET_free (buf);
417 
418  return name_buf;
419 }
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:34
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
#define LOG(kind,...)
Definition: rps-test_util.c:35
static char buf[2048]
unsigned char key[(512/8)]
static unsigned int size
Size of the "table".
Definition: peer.c:67
type for (message) authentication keys
#define GNUNET_malloc(size)
Wrapper around malloc.
char * GNUNET_STRINGS_data_to_string(const void *data, size_t size, char *out, size_t out_size)
Convert binary data to ASCII encoding using CrockfordBase32.
Definition: strings.c:695
#define GNUNET_free(ptr)
Wrapper around free.
Here is the call graph for this function:

◆ string_to_auth_key()

struct GNUNET_CRYPTO_AuthKey string_to_auth_key ( const char *  str)

Definition at line 426 of file rps-test_util.c.

References GNUNET_ERROR_TYPE_WARNING, GNUNET_OK, GNUNET_STRINGS_string_to_data(), GNUNET_CRYPTO_AuthKey::key, and LOG.

Referenced by file_name_cb().

427 {
428  struct GNUNET_CRYPTO_AuthKey auth_key;
429 
430  if (GNUNET_OK !=
432  strlen (str),
433  &auth_key.key,
434  sizeof(struct GNUNET_CRYPTO_AuthKey)))
435  {
436  LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to convert string to data\n");
437  }
438 
439  return auth_key;
440 }
#define LOG(kind,...)
Definition: rps-test_util.c:35
enum GNUNET_GenericReturnValue GNUNET_STRINGS_string_to_data(const char *enc, size_t enclen, void *out, size_t out_size)
Convert CrockfordBase32 encoding back to data.
Definition: strings.c:775
type for (message) authentication keys
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_file_handle()

struct GNUNET_DISK_FileHandle* get_file_handle ( const char *  name)

Get file handle.

If necessary, create file handle and store it with the other file handles.

Parameters
nameName of the file
Returns
File handle

Definition at line 74 of file rps-test_util.c.

References fh, GNUNET_assert, GNUNET_CONTAINER_multihashmap_create(), GNUNET_CONTAINER_multihashmap_get(), GNUNET_CONTAINER_multihashmap_put(), GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY, GNUNET_CRYPTO_hash(), GNUNET_DISK_file_open(), GNUNET_DISK_OPEN_APPEND, GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_GROUP_READ, GNUNET_DISK_PERM_USER_READ, GNUNET_DISK_PERM_USER_WRITE, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_NO, GNUNET_YES, and LOG.

75 {
76  struct GNUNET_HashCode hash;
77  struct GNUNET_DISK_FileHandle *fh;
78 
79  if (NULL == open_files)
80  {
82  GNUNET_NO);
84  "Created map of open files.\n");
85  }
87  strlen (name),
88  &hash);
90  &hash)))
91  return fh;
99  if (NULL == fh)
100  {
102  "Opening file `%s' failed.\n",
103  name);
104  GNUNET_assert (0);
105  }
108  &hash,
109  fh,
111  return fh;
112 }
Create file if it doesn't exist.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static struct GNUNET_CONTAINER_MultiHashMap * open_files
Definition: rps-test_util.c:61
Append to the file.
void * GNUNET_CONTAINER_multihashmap_get(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Given a key find a value in the map matching the key.
#define LOG(kind,...)
Definition: rps-test_util.c:35
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:41
static int fh
Handle to the unique file.
A 512-bit hashcode.
There must only be one value per key; storing a value should fail if a value under the same key alrea...
Open the file for writing.
int GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
const char * name
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open(const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm)
Open a file.
Definition: disk.c:1234
Handle used to access files (and pipes).
Here is the call graph for this function:

◆ close_all_files()

int close_all_files ( )

Close all files that were opened with get_file_handle.

Returns
Success of iterating over files

Definition at line 151 of file rps-test_util.c.

References close_files_iter(), GNUNET_CONTAINER_multihashmap_destroy(), GNUNET_CONTAINER_multihashmap_iterate(), GNUNET_YES, and ret.

Referenced by shutdown_op(), and shutdown_task().

152 {
153  int ret;
154 
155  if (NULL != open_files)
156  {
159  NULL);
161  open_files = NULL;
162  return ret;
163  }
164  return GNUNET_YES;
165 }
int close_files_iter(void *cls, const struct GNUNET_HashCode *key, void *value)
Closes the file of the current entry.
static struct GNUNET_CONTAINER_MultiHashMap * open_files
Definition: rps-test_util.c:61
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
int GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_MulitHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ store_prefix_file_name()

char* store_prefix_file_name ( const unsigned int  index,
const char *  prefix 
)

Definition at line 464 of file rps-test_util.c.

References ensure_folder_exist(), file_name, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_malloc, GNUNET_snprintf(), and GNUNET_SYSERR.

Referenced by post_profiler(), and pre_profiler().

466 {
467  int len_file_name;
468  int out_size;
469  char *file_name;
470  char index_str[64];
471 
473  return NULL;
474  out_size = GNUNET_snprintf (index_str,
475  64,
476  "%u",
477  index);
478  if ((64 < out_size) ||
479  (0 > out_size) )
480  {
482  "Failed to write string to buffer (size: %i, out_size: %i)\n",
483  64,
484  out_size);
485  }
486  len_file_name = (strlen (prefix)
487  + strlen (index_str)
488  + 11)
489  * sizeof(char);
490  file_name = GNUNET_malloc (len_file_name);
491  out_size = GNUNET_snprintf (file_name,
492  len_file_name,
493  "/tmp/rps/%s-%s",
494  prefix,
495  index_str);
496  if ((len_file_name < out_size) ||
497  (0 > out_size) )
498  {
500  "Failed to write string to buffer (size: %i, out_size: %i)\n",
501  len_file_name,
502  out_size);
503  }
504  return file_name;
505 }
static char * file_name
Dump file name.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
static int ensure_folder_exist(void)
Try to ensure that /tmp/rps exists.
#define GNUNET_log(kind,...)
#define GNUNET_malloc(size)
Wrapper around malloc.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ to_file_raw()

void to_file_raw ( const char *  file_name,
const char *  buf,
size_t  size_buf 
)

Definition at line 169 of file rps-test_util.c.

References removetrailingwhitespace::f, GNUNET_DISK_file_close(), GNUNET_DISK_file_open(), GNUNET_DISK_file_write(), GNUNET_DISK_OPEN_APPEND, GNUNET_DISK_OPEN_CREATE, GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_GROUP_READ, GNUNET_DISK_PERM_OTHER_READ, GNUNET_DISK_PERM_USER_READ, GNUNET_DISK_PERM_USER_WRITE, GNUNET_ERROR_TYPE_WARNING, GNUNET_YES, and LOG.

Referenced by profiler_reply_handle(), profiler_reply_handle_info(), and to_file_raw_unaligned().

170 {
171  struct GNUNET_DISK_FileHandle *f;
172  size_t size_written;
173 
174  if (NULL == (f = GNUNET_DISK_file_open (file_name,
182  {
184  "Not able to open file %s\n",
185  file_name);
186  return;
187  }
188 
189  size_written = GNUNET_DISK_file_write (f, buf, size_buf);
190  if (size_buf != size_written)
191  {
193  "Unable to write to file! (Size: %llu, size_written: %llu)\n",
194  (unsigned long long) size_buf,
195  (unsigned long long) size_written);
196 
199  "Unable to close file\n");
200 
201  return;
202  }
204  "Wrote %llu bytes raw.\n",
205  (unsigned long long) size_written);
208  "Unable to close file\n");
209 }
Create file if it doesn&#39;t exist.
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1305
static char * file_name
Dump file name.
Append to the file.
#define LOG(kind,...)
Definition: rps-test_util.c:35
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:686
static char buf[2048]
Open the file for writing.
Everybody can read.
struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open(const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm)
Open a file.
Definition: disk.c:1234
Handle used to access files (and pipes).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ to_file_raw_unaligned()

void to_file_raw_unaligned ( const char *  file_name,
const char *  buf,
size_t  size_buf,
unsigned  bits_needed 
)

Definition at line 213 of file rps-test_util.c.

References B2B, B2B_PAT, bits_needed, buf_unaligned, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_MIN, LOG, num_bits_buf_unaligned, and to_file_raw().

Referenced by profiler_reply_handle(), and profiler_reply_handle_info().

217 {
218  // TODO endianness!
219  GNUNET_assert (size_buf >= (bits_needed / 8));
220  // if (0 == num_bits_buf_unaligned)
221  // {
222  // if (0 == (bits_needed % 8))
223  // {
224  // to_file_raw (file_name, buf, size_buf);
225  // return;
226  // }
227  // to_file_raw (file_name, buf, size_buf - 1);
228  // buf_unaligned = buf[size_buf - 1];
229  // num_bits_buf_unaligned = bits_needed % 8;
230  // return;
231  // }
233  "Was asked to write %u bits\n", bits_needed);
234 
235  char buf_write[size_buf + 1];
236  const unsigned bytes_iter = (0 != bits_needed % 8 ?
237  (bits_needed / 8) + 1 :
238  bits_needed / 8);
239  // TODO what if no iteration happens?
240  unsigned size_buf_write = 0;
242  "num_bits_buf_unaligned: %u\n",
245  "ua args: size_buf: %llu, bits_needed: %u -> iter: %u\n",
246  (unsigned long long) size_buf,
247  bits_needed,
248  bytes_iter);
249  buf_write[0] = buf_unaligned;
250  /* Iterate over input bytes */
251  for (unsigned i = 0; i < bytes_iter; i++)
252  {
253  /* Number of bits needed in this iteration - 8 for all except last iter */
254  unsigned num_bits_needed_iter;
255  /* Mask for bits to actually use */
256  unsigned mask_bits_needed_iter;
257  char byte_input;
258  /* Number of bits needed to align unaligned byte */
259  unsigned num_bits_to_align;
260  /* Number of bits that are to be moved */
261  unsigned num_bits_to_move;
262  /* Mask for bytes to be moved */
263  char mask_input_to_move;
264  /* Masked bits to be moved */
265  char bits_to_move;
266  /* The amount of bits needed to fit the bits to shift to the nearest spot */
267  unsigned distance_shift_bits;
268  /* Shifted bits on the move */
269  char bits_moving;
270  /* (unaligned) byte being filled with bits */
271  char byte_to_fill;
272  /* mask for needed bits of the input byte that have not been moved */
273  char mask_input_leftover;
274  /* needed bits of the input byte that have not been moved */
275  char byte_input_leftover;
276  unsigned num_bits_leftover;
277  // unsigned num_bits_discard;
278  char byte_unaligned_new;
279 
280  if ((bits_needed - (i * 8)) <= 8)
281  {
282  /* last iteration */
283  num_bits_needed_iter = bits_needed - (i * 8);
284  }
285  else
286  {
287  num_bits_needed_iter = 8;
288  }
290  "number of bits needed in this iteration: %u\n",
291  num_bits_needed_iter);
292  mask_bits_needed_iter = ((char) 1 << num_bits_needed_iter) - 1;
294  "mask needed bits (current iter): "B2B_PAT "\n",
295  B2B (mask_bits_needed_iter));
297  "Unaligned byte: "B2B_PAT " (%u bits)\n",
298  B2B (buf_unaligned),
300  byte_input = buf[i];
302  "next whole input byte: "B2B_PAT "\n",
303  B2B (byte_input));
304  byte_input &= mask_bits_needed_iter;
305  num_bits_to_align = 8 - num_bits_buf_unaligned;
307  "input byte, needed bits: "B2B_PAT "\n",
308  B2B (byte_input));
310  "number of bits needed to align unaligned bit: %u\n",
311  num_bits_to_align);
312  num_bits_to_move = GNUNET_MIN (num_bits_to_align, num_bits_needed_iter);
314  "number of bits of new byte to move: %u\n",
315  num_bits_to_move);
316  mask_input_to_move = ((char) 1 << num_bits_to_move) - 1;
318  "mask of bits of new byte to take for moving: "B2B_PAT "\n",
319  B2B (mask_input_to_move));
320  bits_to_move = byte_input & mask_input_to_move;
322  "masked bits of new byte to take for moving: "B2B_PAT "\n",
323  B2B (bits_to_move));
324  distance_shift_bits = num_bits_buf_unaligned;
326  "distance needed to shift bits to their correct spot: %u\n",
327  distance_shift_bits);
328  bits_moving = bits_to_move << distance_shift_bits;
330  "shifted, masked bits of new byte being moved: "B2B_PAT "\n",
331  B2B (bits_moving));
332  byte_to_fill = buf_unaligned | bits_moving;
334  "byte being filled: "B2B_PAT "\n",
335  B2B (byte_to_fill));
337  "pending bytes: %u\n",
338  num_bits_buf_unaligned + num_bits_needed_iter);
339  if (num_bits_buf_unaligned + num_bits_needed_iter >= 8)
340  {
341  /* buf_unaligned was aligned by filling
342  * -> can be written to storage */
343  buf_write[i] = byte_to_fill;
344  size_buf_write++;
345 
346  /* store the leftover, unaligned bits in buffer */
347  mask_input_leftover = mask_bits_needed_iter & (~mask_input_to_move);
349  "mask of leftover bits of new byte: "B2B_PAT "\n",
350  B2B (mask_input_leftover));
351  byte_input_leftover = byte_input & mask_input_leftover;
353  "masked, leftover bits of new byte: "B2B_PAT "\n",
354  B2B (byte_input_leftover));
355  num_bits_leftover = num_bits_needed_iter - num_bits_to_move;
357  "number of unaligned bits left: %u\n",
358  num_bits_leftover);
359  // num_bits_discard = 8 - num_bits_needed_iter;
360  byte_unaligned_new = byte_input_leftover >> num_bits_to_move;
362  "new unaligned byte: "B2B_PAT "\n",
363  B2B (byte_unaligned_new));
364  buf_unaligned = byte_unaligned_new;
365  num_bits_buf_unaligned = num_bits_leftover % 8;
366  }
367  else
368  {
369  /* unaligned buffer still unaligned but 'fuller' */
370  buf_unaligned = byte_to_fill;
372  }
373  }
374  to_file_raw (file_name, buf_write, size_buf_write);
376 }
void to_file_raw(const char *file_name, const char *buf, size_t size_buf)
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static char * file_name
Dump file name.
static unsigned bits_needed
number of bits required to represent the largest peer id
static unsigned num_bits_buf_unaligned
number of bits in unaligned buffer
Definition: rps-test_util.c:59
#define B2B_PAT
Definition: rps-test_util.c:37
#define LOG(kind,...)
Definition: rps-test_util.c:35
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:93
static char buf[2048]
static char buf_unaligned
buffer for storing the unaligned bits for the next write
Definition: rps-test_util.c:54
#define B2B(byte)
Definition: rps-test_util.c:38
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fac()

uint32_t fac ( uint32_t  x)

Factorial.

Parameters
xNumber of which to compute the factorial
Returns
Factorial of x

Definition at line 516 of file rps-test_util.c.

References fac().

Referenced by binom(), fac(), and find_address_cb().

517 {
518  if (1 >= x)
519  {
520  return x;
521  }
522  return x * fac (x - 1);
523 }
uint32_t fac(uint32_t x)
Factorial.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ binom()

uint32_t binom ( uint32_t  n,
uint32_t  k 
)

Binomial coefficient (n choose k)

Parameters
n
k
Returns
Binomial coefficient of n and k

Definition at line 535 of file rps-test_util.c.

References fac().

Referenced by compute_probabilities().

536 {
537  // GNUNET_assert (n >= k);
538  if (k > n)
539  return 0;
540  /* if (0 > n) return 0; - always false */
541  /* if (0 > k) return 0; - always false */
542  if (0 == k)
543  return 1;
544  return fac (n)
545  /
546  fac (k) * fac (n - k);
547 }
uint32_t fac(uint32_t x)
Factorial.
Here is the call graph for this function:
Here is the caller graph for this function: