Coverage Report

Created: 2025-11-11 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Modules/_io/clinic/fileio.c.h
Line
Count
Source
1
/*[clinic input]
2
preserve
3
[clinic start generated code]*/
4
5
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
6
#  include "pycore_gc.h"          // PyGC_Head
7
#  include "pycore_runtime.h"     // _Py_ID()
8
#endif
9
#include "pycore_abstract.h"      // _Py_convert_optional_to_ssize_t()
10
#include "pycore_modsupport.h"    // _PyArg_UnpackKeywords()
11
12
PyDoc_STRVAR(_io_FileIO_close__doc__,
13
"close($self, /)\n"
14
"--\n"
15
"\n"
16
"Close the file.\n"
17
"\n"
18
"A closed file cannot be used for further I/O operations.  close() may be\n"
19
"called more than once without error.");
20
21
#define _IO_FILEIO_CLOSE_METHODDEF    \
22
    {"close", _PyCFunction_CAST(_io_FileIO_close), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_close__doc__},
23
24
static PyObject *
25
_io_FileIO_close_impl(fileio *self, PyTypeObject *cls);
26
27
static PyObject *
28
_io_FileIO_close(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
29
1.46k
{
30
1.46k
    if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) {
31
0
        PyErr_SetString(PyExc_TypeError, "close() takes no arguments");
32
0
        return NULL;
33
0
    }
34
1.46k
    return _io_FileIO_close_impl((fileio *)self, cls);
35
1.46k
}
36
37
PyDoc_STRVAR(_io_FileIO___init____doc__,
38
"FileIO(file, mode=\'r\', closefd=True, opener=None)\n"
39
"--\n"
40
"\n"
41
"Open a file.\n"
42
"\n"
43
"The mode can be \'r\' (default), \'w\', \'x\' or \'a\' for reading,\n"
44
"writing, exclusive creation or appending.  The file will be created if it\n"
45
"doesn\'t exist when opened for writing or appending; it will be truncated\n"
46
"when opened for writing.  A FileExistsError will be raised if it already\n"
47
"exists when opened for creating. Opening a file for creating implies\n"
48
"writing so this mode behaves in a similar way to \'w\'.Add a \'+\' to the mode\n"
49
"to allow simultaneous reading and writing. A custom opener can be used by\n"
50
"passing a callable as *opener*. The underlying file descriptor for the file\n"
51
"object is then obtained by calling opener with (*name*, *flags*).\n"
52
"*opener* must return an open file descriptor (passing os.open as *opener*\n"
53
"results in functionality similar to passing None).");
54
55
static int
56
_io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
57
                         int closefd, PyObject *opener);
58
59
static int
60
_io_FileIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
61
1.53k
{
62
1.53k
    int return_value = -1;
63
1.53k
    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
64
65
1.53k
    #define NUM_KEYWORDS 4
66
1.53k
    static struct {
67
1.53k
        PyGC_Head _this_is_not_used;
68
1.53k
        PyObject_VAR_HEAD
69
1.53k
        Py_hash_t ob_hash;
70
1.53k
        PyObject *ob_item[NUM_KEYWORDS];
71
1.53k
    } _kwtuple = {
72
1.53k
        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
73
1.53k
        .ob_hash = -1,
74
1.53k
        .ob_item = { &_Py_ID(file), &_Py_ID(mode), &_Py_ID(closefd), &_Py_ID(opener), },
75
1.53k
    };
76
1.53k
    #undef NUM_KEYWORDS
77
1.53k
    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
78
79
    #else  // !Py_BUILD_CORE
80
    #  define KWTUPLE NULL
81
    #endif  // !Py_BUILD_CORE
82
83
1.53k
    static const char * const _keywords[] = {"file", "mode", "closefd", "opener", NULL};
84
1.53k
    static _PyArg_Parser _parser = {
85
1.53k
        .keywords = _keywords,
86
1.53k
        .fname = "FileIO",
87
1.53k
        .kwtuple = KWTUPLE,
88
1.53k
    };
89
1.53k
    #undef KWTUPLE
90
1.53k
    PyObject *argsbuf[4];
91
1.53k
    PyObject * const *fastargs;
92
1.53k
    Py_ssize_t nargs = PyTuple_GET_SIZE(args);
93
1.53k
    Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
94
1.53k
    PyObject *nameobj;
95
1.53k
    const char *mode = "r";
96
1.53k
    int closefd = 1;
97
1.53k
    PyObject *opener = Py_None;
98
99
1.53k
    fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser,
100
1.53k
            /*minpos*/ 1, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
101
1.53k
    if (!fastargs) {
102
0
        goto exit;
103
0
    }
104
1.53k
    nameobj = fastargs[0];
105
1.53k
    if (!noptargs) {
106
0
        goto skip_optional_pos;
107
0
    }
108
1.53k
    if (fastargs[1]) {
109
1.53k
        if (!PyUnicode_Check(fastargs[1])) {
110
0
            _PyArg_BadArgument("FileIO", "argument 'mode'", "str", fastargs[1]);
111
0
            goto exit;
112
0
        }
113
1.53k
        Py_ssize_t mode_length;
114
1.53k
        mode = PyUnicode_AsUTF8AndSize(fastargs[1], &mode_length);
115
1.53k
        if (mode == NULL) {
116
0
            goto exit;
117
0
        }
118
1.53k
        if (strlen(mode) != (size_t)mode_length) {
119
0
            PyErr_SetString(PyExc_ValueError, "embedded null character");
120
0
            goto exit;
121
0
        }
122
1.53k
        if (!--noptargs) {
123
260
            goto skip_optional_pos;
124
260
        }
125
1.53k
    }
126
1.27k
    if (fastargs[2]) {
127
1.27k
        closefd = PyObject_IsTrue(fastargs[2]);
128
1.27k
        if (closefd < 0) {
129
0
            goto exit;
130
0
        }
131
1.27k
        if (!--noptargs) {
132
0
            goto skip_optional_pos;
133
0
        }
134
1.27k
    }
135
1.27k
    opener = fastargs[3];
136
1.53k
skip_optional_pos:
137
1.53k
    return_value = _io_FileIO___init___impl((fileio *)self, nameobj, mode, closefd, opener);
138
139
1.53k
exit:
140
1.53k
    return return_value;
141
1.53k
}
142
143
PyDoc_STRVAR(_io_FileIO_fileno__doc__,
144
"fileno($self, /)\n"
145
"--\n"
146
"\n"
147
"Return the underlying file descriptor (an integer).");
148
149
#define _IO_FILEIO_FILENO_METHODDEF    \
150
    {"fileno", (PyCFunction)_io_FileIO_fileno, METH_NOARGS, _io_FileIO_fileno__doc__},
151
152
static PyObject *
153
_io_FileIO_fileno_impl(fileio *self);
154
155
static PyObject *
156
_io_FileIO_fileno(PyObject *self, PyObject *Py_UNUSED(ignored))
157
0
{
158
0
    return _io_FileIO_fileno_impl((fileio *)self);
159
0
}
160
161
PyDoc_STRVAR(_io_FileIO_readable__doc__,
162
"readable($self, /)\n"
163
"--\n"
164
"\n"
165
"True if file was opened in a read mode.");
166
167
#define _IO_FILEIO_READABLE_METHODDEF    \
168
    {"readable", (PyCFunction)_io_FileIO_readable, METH_NOARGS, _io_FileIO_readable__doc__},
169
170
static PyObject *
171
_io_FileIO_readable_impl(fileio *self);
172
173
static PyObject *
174
_io_FileIO_readable(PyObject *self, PyObject *Py_UNUSED(ignored))
175
1.25k
{
176
1.25k
    return _io_FileIO_readable_impl((fileio *)self);
177
1.25k
}
178
179
PyDoc_STRVAR(_io_FileIO_writable__doc__,
180
"writable($self, /)\n"
181
"--\n"
182
"\n"
183
"True if file was opened in a write mode.");
184
185
#define _IO_FILEIO_WRITABLE_METHODDEF    \
186
    {"writable", (PyCFunction)_io_FileIO_writable, METH_NOARGS, _io_FileIO_writable__doc__},
187
188
static PyObject *
189
_io_FileIO_writable_impl(fileio *self);
190
191
static PyObject *
192
_io_FileIO_writable(PyObject *self, PyObject *Py_UNUSED(ignored))
193
88
{
194
88
    return _io_FileIO_writable_impl((fileio *)self);
195
88
}
196
197
PyDoc_STRVAR(_io_FileIO_seekable__doc__,
198
"seekable($self, /)\n"
199
"--\n"
200
"\n"
201
"True if file supports random-access.");
202
203
#define _IO_FILEIO_SEEKABLE_METHODDEF    \
204
    {"seekable", (PyCFunction)_io_FileIO_seekable, METH_NOARGS, _io_FileIO_seekable__doc__},
205
206
static PyObject *
207
_io_FileIO_seekable_impl(fileio *self);
208
209
static PyObject *
210
_io_FileIO_seekable(PyObject *self, PyObject *Py_UNUSED(ignored))
211
78
{
212
78
    return _io_FileIO_seekable_impl((fileio *)self);
213
78
}
214
215
PyDoc_STRVAR(_io_FileIO_readinto__doc__,
216
"readinto($self, buffer, /)\n"
217
"--\n"
218
"\n"
219
"Same as RawIOBase.readinto().");
220
221
#define _IO_FILEIO_READINTO_METHODDEF    \
222
    {"readinto", _PyCFunction_CAST(_io_FileIO_readinto), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_readinto__doc__},
223
224
static PyObject *
225
_io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer);
226
227
static PyObject *
228
_io_FileIO_readinto(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
229
8
{
230
8
    PyObject *return_value = NULL;
231
8
    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
232
8
    #  define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
233
    #else
234
    #  define KWTUPLE NULL
235
    #endif
236
237
8
    static const char * const _keywords[] = {"", NULL};
238
8
    static _PyArg_Parser _parser = {
239
8
        .keywords = _keywords,
240
8
        .fname = "readinto",
241
8
        .kwtuple = KWTUPLE,
242
8
    };
243
8
    #undef KWTUPLE
244
8
    PyObject *argsbuf[1];
245
8
    Py_buffer buffer = {NULL, NULL};
246
247
8
    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
248
8
            /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
249
8
    if (!args) {
250
0
        goto exit;
251
0
    }
252
8
    if (PyObject_GetBuffer(args[0], &buffer, PyBUF_WRITABLE) < 0) {
253
0
        _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]);
254
0
        goto exit;
255
0
    }
256
8
    return_value = _io_FileIO_readinto_impl((fileio *)self, cls, &buffer);
257
258
8
exit:
259
    /* Cleanup for buffer */
260
8
    if (buffer.obj) {
261
8
       PyBuffer_Release(&buffer);
262
8
    }
263
264
8
    return return_value;
265
8
}
266
267
PyDoc_STRVAR(_io_FileIO_readall__doc__,
268
"readall($self, /)\n"
269
"--\n"
270
"\n"
271
"Read all data from the file, returned as bytes.\n"
272
"\n"
273
"Reads until either there is an error or read() returns size 0 (indicates EOF).\n"
274
"If the file is already at EOF, returns an empty bytes object.\n"
275
"\n"
276
"In non-blocking mode, returns as much data as could be read before EAGAIN. If no\n"
277
"data is available (EAGAIN is returned before bytes are read) returns None.");
278
279
#define _IO_FILEIO_READALL_METHODDEF    \
280
    {"readall", (PyCFunction)_io_FileIO_readall, METH_NOARGS, _io_FileIO_readall__doc__},
281
282
static PyObject *
283
_io_FileIO_readall_impl(fileio *self);
284
285
static PyObject *
286
_io_FileIO_readall(PyObject *self, PyObject *Py_UNUSED(ignored))
287
1.20k
{
288
1.20k
    return _io_FileIO_readall_impl((fileio *)self);
289
1.20k
}
290
291
PyDoc_STRVAR(_io_FileIO_read__doc__,
292
"read($self, size=-1, /)\n"
293
"--\n"
294
"\n"
295
"Read at most size bytes, returned as bytes.\n"
296
"\n"
297
"If size is less than 0, read all bytes in the file making multiple read calls.\n"
298
"See ``FileIO.readall``.\n"
299
"\n"
300
"Attempts to make only one system call, retrying only per PEP 475 (EINTR). This\n"
301
"means less data may be returned than requested.\n"
302
"\n"
303
"In non-blocking mode, returns None if no data is available. Return an empty\n"
304
"bytes object at EOF.");
305
306
#define _IO_FILEIO_READ_METHODDEF    \
307
    {"read", _PyCFunction_CAST(_io_FileIO_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_read__doc__},
308
309
static PyObject *
310
_io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size);
311
312
static PyObject *
313
_io_FileIO_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
314
0
{
315
0
    PyObject *return_value = NULL;
316
0
    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
317
0
    #  define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
318
    #else
319
    #  define KWTUPLE NULL
320
    #endif
321
322
0
    static const char * const _keywords[] = {"", NULL};
323
0
    static _PyArg_Parser _parser = {
324
0
        .keywords = _keywords,
325
0
        .fname = "read",
326
0
        .kwtuple = KWTUPLE,
327
0
    };
328
0
    #undef KWTUPLE
329
0
    PyObject *argsbuf[1];
330
0
    Py_ssize_t size = -1;
331
332
0
    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
333
0
            /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
334
0
    if (!args) {
335
0
        goto exit;
336
0
    }
337
0
    if (nargs < 1) {
338
0
        goto skip_optional_posonly;
339
0
    }
340
0
    if (!_Py_convert_optional_to_ssize_t(args[0], &size)) {
341
0
        goto exit;
342
0
    }
343
0
skip_optional_posonly:
344
0
    return_value = _io_FileIO_read_impl((fileio *)self, cls, size);
345
346
0
exit:
347
0
    return return_value;
348
0
}
349
350
PyDoc_STRVAR(_io_FileIO_write__doc__,
351
"write($self, b, /)\n"
352
"--\n"
353
"\n"
354
"Write buffer b to file, return number of bytes written.\n"
355
"\n"
356
"Only makes one system call, so not all of the data may be written.\n"
357
"The number of bytes actually written is returned.  In non-blocking mode,\n"
358
"returns None if the write would block.");
359
360
#define _IO_FILEIO_WRITE_METHODDEF    \
361
    {"write", _PyCFunction_CAST(_io_FileIO_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_write__doc__},
362
363
static PyObject *
364
_io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b);
365
366
static PyObject *
367
_io_FileIO_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
368
260
{
369
260
    PyObject *return_value = NULL;
370
260
    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
371
260
    #  define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
372
    #else
373
    #  define KWTUPLE NULL
374
    #endif
375
376
260
    static const char * const _keywords[] = {"", NULL};
377
260
    static _PyArg_Parser _parser = {
378
260
        .keywords = _keywords,
379
260
        .fname = "write",
380
260
        .kwtuple = KWTUPLE,
381
260
    };
382
260
    #undef KWTUPLE
383
260
    PyObject *argsbuf[1];
384
260
    Py_buffer b = {NULL, NULL};
385
386
260
    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
387
260
            /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
388
260
    if (!args) {
389
0
        goto exit;
390
0
    }
391
260
    if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) {
392
0
        goto exit;
393
0
    }
394
260
    return_value = _io_FileIO_write_impl((fileio *)self, cls, &b);
395
396
260
exit:
397
    /* Cleanup for b */
398
260
    if (b.obj) {
399
260
       PyBuffer_Release(&b);
400
260
    }
401
402
260
    return return_value;
403
260
}
404
405
PyDoc_STRVAR(_io_FileIO_seek__doc__,
406
"seek($self, pos, whence=0, /)\n"
407
"--\n"
408
"\n"
409
"Move to new file position and return the file position.\n"
410
"\n"
411
"Argument offset is a byte count.  Optional argument whence defaults to\n"
412
"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n"
413
"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n"
414
"and SEEK_END or 2 (move relative to end of file, usually negative, although\n"
415
"many platforms allow seeking beyond the end of a file).\n"
416
"\n"
417
"Note that not all file objects are seekable.");
418
419
#define _IO_FILEIO_SEEK_METHODDEF    \
420
    {"seek", _PyCFunction_CAST(_io_FileIO_seek), METH_FASTCALL, _io_FileIO_seek__doc__},
421
422
static PyObject *
423
_io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence);
424
425
static PyObject *
426
_io_FileIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
427
12
{
428
12
    PyObject *return_value = NULL;
429
12
    PyObject *pos;
430
12
    int whence = 0;
431
432
12
    if (!_PyArg_CheckPositional("seek", nargs, 1, 2)) {
433
0
        goto exit;
434
0
    }
435
12
    pos = args[0];
436
12
    if (nargs < 2) {
437
0
        goto skip_optional;
438
0
    }
439
12
    whence = PyLong_AsInt(args[1]);
440
12
    if (whence == -1 && PyErr_Occurred()) {
441
0
        goto exit;
442
0
    }
443
12
skip_optional:
444
12
    return_value = _io_FileIO_seek_impl((fileio *)self, pos, whence);
445
446
12
exit:
447
12
    return return_value;
448
12
}
449
450
PyDoc_STRVAR(_io_FileIO_tell__doc__,
451
"tell($self, /)\n"
452
"--\n"
453
"\n"
454
"Current file position.\n"
455
"\n"
456
"Can raise OSError for non seekable files.");
457
458
#define _IO_FILEIO_TELL_METHODDEF    \
459
    {"tell", (PyCFunction)_io_FileIO_tell, METH_NOARGS, _io_FileIO_tell__doc__},
460
461
static PyObject *
462
_io_FileIO_tell_impl(fileio *self);
463
464
static PyObject *
465
_io_FileIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored))
466
1.32k
{
467
1.32k
    return _io_FileIO_tell_impl((fileio *)self);
468
1.32k
}
469
470
#if defined(HAVE_FTRUNCATE)
471
472
PyDoc_STRVAR(_io_FileIO_truncate__doc__,
473
"truncate($self, size=None, /)\n"
474
"--\n"
475
"\n"
476
"Truncate the file to at most size bytes and return the truncated size.\n"
477
"\n"
478
"Size defaults to the current file position, as returned by tell().\n"
479
"The current file position is changed to the value of size.");
480
481
#define _IO_FILEIO_TRUNCATE_METHODDEF    \
482
    {"truncate", _PyCFunction_CAST(_io_FileIO_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_truncate__doc__},
483
484
static PyObject *
485
_io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj);
486
487
static PyObject *
488
_io_FileIO_truncate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
489
0
{
490
0
    PyObject *return_value = NULL;
491
0
    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
492
0
    #  define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty)
493
    #else
494
    #  define KWTUPLE NULL
495
    #endif
496
497
0
    static const char * const _keywords[] = {"", NULL};
498
0
    static _PyArg_Parser _parser = {
499
0
        .keywords = _keywords,
500
0
        .fname = "truncate",
501
0
        .kwtuple = KWTUPLE,
502
0
    };
503
0
    #undef KWTUPLE
504
0
    PyObject *argsbuf[1];
505
0
    PyObject *posobj = Py_None;
506
507
0
    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
508
0
            /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
509
0
    if (!args) {
510
0
        goto exit;
511
0
    }
512
0
    if (nargs < 1) {
513
0
        goto skip_optional_posonly;
514
0
    }
515
0
    posobj = args[0];
516
0
skip_optional_posonly:
517
0
    return_value = _io_FileIO_truncate_impl((fileio *)self, cls, posobj);
518
519
0
exit:
520
0
    return return_value;
521
0
}
522
523
#endif /* defined(HAVE_FTRUNCATE) */
524
525
PyDoc_STRVAR(_io_FileIO_isatty__doc__,
526
"isatty($self, /)\n"
527
"--\n"
528
"\n"
529
"True if the file is connected to a TTY device.");
530
531
#define _IO_FILEIO_ISATTY_METHODDEF    \
532
    {"isatty", (PyCFunction)_io_FileIO_isatty, METH_NOARGS, _io_FileIO_isatty__doc__},
533
534
static PyObject *
535
_io_FileIO_isatty_impl(fileio *self);
536
537
static PyObject *
538
_io_FileIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored))
539
66
{
540
66
    return _io_FileIO_isatty_impl((fileio *)self);
541
66
}
542
543
#ifndef _IO_FILEIO_TRUNCATE_METHODDEF
544
    #define _IO_FILEIO_TRUNCATE_METHODDEF
545
#endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */
546
/*[clinic end generated code: output=1902fac9e39358aa input=a9049054013a1b77]*/