cui-llama.rn 1.4.4 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/CMakeLists.txt +9 -2
- package/android/src/main/jni.cpp +54 -34
- package/android/src/main/jniLibs/arm64-v8a/librnllama.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/librnllama_v8.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/librnllama_v8_2.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/librnllama_v8_2_dotprod.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/librnllama_v8_2_dotprod_i8mm.so +0 -0
- package/android/src/main/jniLibs/arm64-v8a/librnllama_v8_2_i8mm.so +0 -0
- package/android/src/main/jniLibs/x86_64/librnllama.so +0 -0
- package/android/src/main/jniLibs/x86_64/librnllama_x86_64.so +0 -0
- package/cpp/binary-ops.cpp +158 -0
- package/cpp/binary-ops.h +16 -0
- package/cpp/chat.cpp +1769 -1085
- package/cpp/chat.h +143 -0
- package/cpp/common.cpp +1562 -1996
- package/cpp/common.h +677 -744
- package/cpp/cpu-common.h +72 -0
- package/cpp/ggml-alloc.c +1039 -1030
- package/cpp/ggml-alloc.h +1 -1
- package/cpp/ggml-backend-impl.h +255 -255
- package/cpp/ggml-backend-reg.cpp +586 -582
- package/cpp/ggml-backend.cpp +2004 -2002
- package/cpp/ggml-backend.h +354 -354
- package/cpp/ggml-common.h +1857 -1851
- package/cpp/ggml-cpp.h +39 -39
- package/cpp/ggml-cpu-aarch64.cpp +5725 -4247
- package/cpp/ggml-cpu-aarch64.h +8 -8
- package/cpp/ggml-cpu-impl.h +512 -380
- package/cpp/ggml-cpu-quants.c +13026 -11517
- package/cpp/ggml-cpu-traits.cpp +36 -36
- package/cpp/ggml-cpu-traits.h +38 -38
- package/cpp/ggml-cpu.c +3438 -14485
- package/cpp/ggml-cpu.cpp +655 -633
- package/cpp/ggml-cpu.h +138 -135
- package/cpp/ggml-impl.h +594 -567
- package/cpp/ggml-metal-impl.h +312 -3
- package/cpp/ggml-metal.h +66 -66
- package/cpp/ggml-metal.m +5360 -5002
- package/cpp/ggml-opt.cpp +854 -854
- package/cpp/ggml-opt.h +216 -216
- package/cpp/ggml-quants.c +5238 -5238
- package/cpp/ggml-threading.h +14 -14
- package/cpp/ggml.c +6618 -6524
- package/cpp/ggml.h +2222 -2194
- package/cpp/gguf.cpp +1330 -1329
- package/cpp/gguf.h +202 -202
- package/cpp/json-schema-to-grammar.cpp +1024 -1025
- package/cpp/json-schema-to-grammar.h +21 -22
- package/cpp/json.hpp +24766 -24766
- package/cpp/llama-adapter.cpp +382 -347
- package/cpp/llama-adapter.h +76 -74
- package/cpp/llama-arch.cpp +1714 -1492
- package/cpp/llama-arch.h +428 -402
- package/cpp/llama-batch.cpp +368 -368
- package/cpp/llama-batch.h +88 -88
- package/cpp/llama-chat.cpp +640 -587
- package/cpp/llama-chat.h +56 -53
- package/cpp/llama-context.cpp +2831 -1775
- package/cpp/llama-context.h +265 -128
- package/cpp/llama-cparams.cpp +1 -1
- package/cpp/llama-cparams.h +38 -37
- package/cpp/llama-cpp.h +30 -30
- package/cpp/llama-grammar.cpp +1219 -1219
- package/cpp/llama-grammar.h +173 -164
- package/cpp/llama-graph.cpp +1695 -0
- package/cpp/llama-graph.h +592 -0
- package/cpp/llama-hparams.cpp +79 -71
- package/cpp/llama-hparams.h +156 -139
- package/cpp/llama-impl.cpp +167 -167
- package/cpp/llama-impl.h +61 -61
- package/cpp/llama-io.cpp +15 -0
- package/cpp/llama-io.h +35 -0
- package/cpp/llama-kv-cache.cpp +1380 -718
- package/cpp/llama-kv-cache.h +213 -218
- package/cpp/llama-memory.cpp +1 -0
- package/cpp/llama-memory.h +21 -0
- package/cpp/llama-mmap.cpp +600 -590
- package/cpp/llama-mmap.h +68 -68
- package/cpp/llama-model-loader.cpp +1129 -1124
- package/cpp/llama-model-loader.h +169 -167
- package/cpp/llama-model.cpp +13080 -4023
- package/cpp/llama-model.h +409 -370
- package/cpp/llama-sampling.cpp +2563 -2525
- package/cpp/llama-sampling.h +32 -32
- package/cpp/llama-vocab.cpp +3295 -3252
- package/cpp/llama-vocab.h +125 -125
- package/cpp/llama.cpp +351 -10137
- package/cpp/llama.h +1434 -1340
- package/cpp/log.cpp +427 -423
- package/cpp/log.h +132 -132
- package/cpp/{chat-template.hpp → minja/chat-template.hpp} +537 -529
- package/cpp/{minja.hpp → minja/minja.hpp} +2941 -2883
- package/cpp/ops.cpp +8723 -0
- package/cpp/ops.h +128 -0
- package/cpp/rn-llama.cpp +45 -71
- package/cpp/rn-llama.h +3 -3
- package/cpp/sampling.cpp +573 -532
- package/cpp/sgemm.cpp +3043 -2598
- package/cpp/sgemm.h +14 -14
- package/cpp/simd-mappings.h +888 -0
- package/cpp/speculative.cpp +278 -277
- package/cpp/speculative.h +28 -28
- package/cpp/unary-ops.cpp +186 -0
- package/cpp/unary-ops.h +28 -0
- package/cpp/vec.cpp +258 -0
- package/cpp/vec.h +802 -0
- package/ios/CMakeLists.txt +5 -2
- package/ios/RNLlama.mm +2 -2
- package/ios/RNLlamaContext.mm +40 -24
- package/package.json +1 -1
- package/src/NativeRNLlama.ts +6 -4
- package/src/index.ts +3 -1
- package/android/src/main/build-arm64/CMakeCache.txt +0 -429
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CMakeCCompiler.cmake +0 -81
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CMakeCXXCompiler.cmake +0 -101
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CMakeDetermineCompilerABI_C.bin +0 -0
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CMakeDetermineCompilerABI_CXX.bin +0 -0
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CMakeSystem.cmake +0 -15
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CompilerIdC/CMakeCCompilerId.c +0 -904
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CompilerIdC/CMakeCCompilerId.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CompilerIdCXX/CMakeCXXCompilerId.cpp +0 -919
- package/android/src/main/build-arm64/CMakeFiles/3.31.4/CompilerIdCXX/CMakeCXXCompilerId.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/CMakeConfigureLog.yaml +0 -431
- package/android/src/main/build-arm64/CMakeFiles/CMakeDirectoryInformation.cmake +0 -16
- package/android/src/main/build-arm64/CMakeFiles/Makefile.cmake +0 -165
- package/android/src/main/build-arm64/CMakeFiles/Makefile2 +0 -297
- package/android/src/main/build-arm64/CMakeFiles/Progress/1 +0 -1
- package/android/src/main/build-arm64/CMakeFiles/Progress/2 +0 -1
- package/android/src/main/build-arm64/CMakeFiles/Progress/3 +0 -1
- package/android/src/main/build-arm64/CMakeFiles/Progress/4 +0 -1
- package/android/src/main/build-arm64/CMakeFiles/Progress/5 +0 -1
- package/android/src/main/build-arm64/CMakeFiles/Progress/6 +0 -1
- package/android/src/main/build-arm64/CMakeFiles/Progress/count.txt +0 -1
- package/android/src/main/build-arm64/CMakeFiles/TargetDirectories.txt +0 -8
- package/android/src/main/build-arm64/CMakeFiles/cmake.check_cache +0 -1
- package/android/src/main/build-arm64/CMakeFiles/progress.marks +0 -1
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-alloc.c.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-alloc.c.o.d +0 -58
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-backend-reg.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-backend-reg.cpp.o.d +0 -756
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-backend.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-backend.cpp.o.d +0 -709
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu-aarch64.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu-aarch64.cpp.o.d +0 -714
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu-quants.c.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu-quants.c.o.d +0 -62
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu-traits.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu-traits.cpp.o.d +0 -708
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu.c.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu.c.o.d +0 -113
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-cpu.cpp.o.d +0 -713
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-opt.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-opt.cpp.o.d +0 -763
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-quants.c.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-quants.c.o.d +0 -61
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-threading.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml-threading.cpp.o.d +0 -707
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml.c.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/ggml.c.o.d +0 -104
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/gguf.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/gguf.cpp.o.d +0 -714
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/log.cpp.o +0 -0
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/D_/dev/react-native/cui-llama.rn/cpp/log.cpp.o.d +0 -723
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/DependInfo.cmake +0 -62
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/build.make +0 -722
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/cmake_clean.cmake +0 -89
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/compiler_depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/compiler_depend.ts +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/flags.make +0 -17
- package/android/src/main/build-arm64/CMakeFiles/rnllama.dir/progress.make +0 -41
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8.dir/DependInfo.cmake +0 -62
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8.dir/build.make +0 -722
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8.dir/cmake_clean.cmake +0 -89
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8.dir/compiler_depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8.dir/compiler_depend.ts +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8.dir/depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8.dir/flags.make +0 -17
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8.dir/progress.make +0 -41
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2.dir/DependInfo.cmake +0 -62
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2.dir/build.make +0 -722
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2.dir/cmake_clean.cmake +0 -89
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2.dir/compiler_depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2.dir/compiler_depend.ts +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2.dir/depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2.dir/flags.make +0 -17
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2.dir/progress.make +0 -41
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod.dir/DependInfo.cmake +0 -62
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod.dir/build.make +0 -722
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod.dir/cmake_clean.cmake +0 -89
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod.dir/compiler_depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod.dir/compiler_depend.ts +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod.dir/depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod.dir/flags.make +0 -17
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod.dir/progress.make +0 -41
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod_i8mm.dir/DependInfo.cmake +0 -62
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod_i8mm.dir/build.make +0 -722
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod_i8mm.dir/cmake_clean.cmake +0 -89
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod_i8mm.dir/compiler_depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod_i8mm.dir/compiler_depend.ts +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod_i8mm.dir/depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod_i8mm.dir/flags.make +0 -17
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_dotprod_i8mm.dir/progress.make +0 -41
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_i8mm.dir/DependInfo.cmake +0 -62
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_i8mm.dir/build.make +0 -722
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_i8mm.dir/cmake_clean.cmake +0 -89
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_i8mm.dir/compiler_depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_i8mm.dir/compiler_depend.ts +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_i8mm.dir/depend.make +0 -2
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_i8mm.dir/flags.make +0 -17
- package/android/src/main/build-arm64/CMakeFiles/rnllama_v8_2_i8mm.dir/progress.make +0 -41
- package/android/src/main/build-arm64/Makefile +0 -1862
- package/android/src/main/build-arm64/cmake_install.cmake +0 -66
- package/cpp/chat.hpp +0 -55
- package/cpp/rn-llama.hpp +0 -913
package/cpp/log.cpp
CHANGED
@@ -1,423 +1,427 @@
|
|
1
|
-
#include "log.h"
|
2
|
-
|
3
|
-
#include <chrono>
|
4
|
-
#include <condition_variable>
|
5
|
-
#include <cstdarg>
|
6
|
-
#include <cstdio>
|
7
|
-
#include <mutex>
|
8
|
-
#include <sstream>
|
9
|
-
#include <thread>
|
10
|
-
#include <vector>
|
11
|
-
|
12
|
-
#if defined(__ANDROID__) && defined(RNLLAMA_ANDROID_ENABLE_LOGGING)
|
13
|
-
#include <android/log.h>
|
14
|
-
#endif
|
15
|
-
|
16
|
-
int common_log_verbosity_thold = LOG_DEFAULT_LLAMA;
|
17
|
-
|
18
|
-
void common_log_set_verbosity_thold(int verbosity) {
|
19
|
-
common_log_verbosity_thold = verbosity;
|
20
|
-
}
|
21
|
-
|
22
|
-
static int64_t t_us() {
|
23
|
-
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
24
|
-
}
|
25
|
-
|
26
|
-
// colors
|
27
|
-
enum common_log_col : int {
|
28
|
-
COMMON_LOG_COL_DEFAULT = 0,
|
29
|
-
COMMON_LOG_COL_BOLD,
|
30
|
-
COMMON_LOG_COL_RED,
|
31
|
-
COMMON_LOG_COL_GREEN,
|
32
|
-
COMMON_LOG_COL_YELLOW,
|
33
|
-
COMMON_LOG_COL_BLUE,
|
34
|
-
COMMON_LOG_COL_MAGENTA,
|
35
|
-
COMMON_LOG_COL_CYAN,
|
36
|
-
COMMON_LOG_COL_WHITE,
|
37
|
-
};
|
38
|
-
|
39
|
-
// disable colors by default
|
40
|
-
static std::vector<const char *> g_col = {
|
41
|
-
"",
|
42
|
-
"",
|
43
|
-
"",
|
44
|
-
"",
|
45
|
-
"",
|
46
|
-
"",
|
47
|
-
"",
|
48
|
-
"",
|
49
|
-
"",
|
50
|
-
};
|
51
|
-
|
52
|
-
struct common_log_entry {
|
53
|
-
enum lm_ggml_log_level level;
|
54
|
-
|
55
|
-
bool prefix;
|
56
|
-
|
57
|
-
int64_t timestamp;
|
58
|
-
|
59
|
-
std::vector<char> msg;
|
60
|
-
|
61
|
-
// signals the worker thread to stop
|
62
|
-
bool is_end;
|
63
|
-
|
64
|
-
#if defined(__ANDROID__) && defined(RNLLAMA_ANDROID_ENABLE_LOGGING)
|
65
|
-
void android_print() const {
|
66
|
-
int android_log_priority;
|
67
|
-
switch (level) {
|
68
|
-
case LM_GGML_LOG_LEVEL_INFO:
|
69
|
-
android_log_priority = ANDROID_LOG_INFO;
|
70
|
-
break;
|
71
|
-
case LM_GGML_LOG_LEVEL_WARN:
|
72
|
-
android_log_priority = ANDROID_LOG_WARN;
|
73
|
-
break;
|
74
|
-
case LM_GGML_LOG_LEVEL_ERROR:
|
75
|
-
android_log_priority = ANDROID_LOG_ERROR;
|
76
|
-
break;
|
77
|
-
case LM_GGML_LOG_LEVEL_DEBUG:
|
78
|
-
android_log_priority = ANDROID_LOG_DEBUG;
|
79
|
-
break;
|
80
|
-
default:
|
81
|
-
android_log_priority = ANDROID_LOG_DEFAULT;
|
82
|
-
break;
|
83
|
-
}
|
84
|
-
|
85
|
-
const char * tag = "RNLLAMA_LOG_ANDROID";
|
86
|
-
__android_log_print(android_log_priority, tag, "%s", msg.data());
|
87
|
-
}
|
88
|
-
#endif
|
89
|
-
|
90
|
-
void print(FILE * file = nullptr) const {
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
(int) (timestamp
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
case
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
entry.
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
running
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
}
|
291
|
-
|
292
|
-
cur.
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
running
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
if (
|
333
|
-
file
|
334
|
-
}
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
g_col[
|
350
|
-
g_col[
|
351
|
-
g_col[
|
352
|
-
g_col[
|
353
|
-
g_col[
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
}
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
struct common_log *
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
log
|
392
|
-
}
|
393
|
-
|
394
|
-
void
|
395
|
-
log->
|
396
|
-
}
|
397
|
-
|
398
|
-
void
|
399
|
-
|
400
|
-
}
|
401
|
-
|
402
|
-
void
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
}
|
412
|
-
|
413
|
-
void
|
414
|
-
log->
|
415
|
-
}
|
416
|
-
|
417
|
-
void
|
418
|
-
log->
|
419
|
-
}
|
420
|
-
|
421
|
-
void
|
422
|
-
log->
|
423
|
-
}
|
1
|
+
#include "log.h"
|
2
|
+
|
3
|
+
#include <chrono>
|
4
|
+
#include <condition_variable>
|
5
|
+
#include <cstdarg>
|
6
|
+
#include <cstdio>
|
7
|
+
#include <mutex>
|
8
|
+
#include <sstream>
|
9
|
+
#include <thread>
|
10
|
+
#include <vector>
|
11
|
+
|
12
|
+
#if defined(__ANDROID__) && defined(RNLLAMA_ANDROID_ENABLE_LOGGING)
|
13
|
+
#include <android/log.h>
|
14
|
+
#endif
|
15
|
+
|
16
|
+
int common_log_verbosity_thold = LOG_DEFAULT_LLAMA;
|
17
|
+
|
18
|
+
void common_log_set_verbosity_thold(int verbosity) {
|
19
|
+
common_log_verbosity_thold = verbosity;
|
20
|
+
}
|
21
|
+
|
22
|
+
static int64_t t_us() {
|
23
|
+
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
24
|
+
}
|
25
|
+
|
26
|
+
// colors
|
27
|
+
enum common_log_col : int {
|
28
|
+
COMMON_LOG_COL_DEFAULT = 0,
|
29
|
+
COMMON_LOG_COL_BOLD,
|
30
|
+
COMMON_LOG_COL_RED,
|
31
|
+
COMMON_LOG_COL_GREEN,
|
32
|
+
COMMON_LOG_COL_YELLOW,
|
33
|
+
COMMON_LOG_COL_BLUE,
|
34
|
+
COMMON_LOG_COL_MAGENTA,
|
35
|
+
COMMON_LOG_COL_CYAN,
|
36
|
+
COMMON_LOG_COL_WHITE,
|
37
|
+
};
|
38
|
+
|
39
|
+
// disable colors by default
|
40
|
+
static std::vector<const char *> g_col = {
|
41
|
+
"",
|
42
|
+
"",
|
43
|
+
"",
|
44
|
+
"",
|
45
|
+
"",
|
46
|
+
"",
|
47
|
+
"",
|
48
|
+
"",
|
49
|
+
"",
|
50
|
+
};
|
51
|
+
|
52
|
+
struct common_log_entry {
|
53
|
+
enum lm_ggml_log_level level;
|
54
|
+
|
55
|
+
bool prefix;
|
56
|
+
|
57
|
+
int64_t timestamp;
|
58
|
+
|
59
|
+
std::vector<char> msg;
|
60
|
+
|
61
|
+
// signals the worker thread to stop
|
62
|
+
bool is_end;
|
63
|
+
|
64
|
+
#if defined(__ANDROID__) && defined(RNLLAMA_ANDROID_ENABLE_LOGGING)
|
65
|
+
void android_print() const {
|
66
|
+
int android_log_priority;
|
67
|
+
switch (level) {
|
68
|
+
case LM_GGML_LOG_LEVEL_INFO:
|
69
|
+
android_log_priority = ANDROID_LOG_INFO;
|
70
|
+
break;
|
71
|
+
case LM_GGML_LOG_LEVEL_WARN:
|
72
|
+
android_log_priority = ANDROID_LOG_WARN;
|
73
|
+
break;
|
74
|
+
case LM_GGML_LOG_LEVEL_ERROR:
|
75
|
+
android_log_priority = ANDROID_LOG_ERROR;
|
76
|
+
break;
|
77
|
+
case LM_GGML_LOG_LEVEL_DEBUG:
|
78
|
+
android_log_priority = ANDROID_LOG_DEBUG;
|
79
|
+
break;
|
80
|
+
default:
|
81
|
+
android_log_priority = ANDROID_LOG_DEFAULT;
|
82
|
+
break;
|
83
|
+
}
|
84
|
+
|
85
|
+
const char * tag = "RNLLAMA_LOG_ANDROID";
|
86
|
+
__android_log_print(android_log_priority, tag, "%s", msg.data());
|
87
|
+
}
|
88
|
+
#endif
|
89
|
+
|
90
|
+
void print(FILE * file = nullptr) const {
|
91
|
+
#if defined(__ANDROID__) && defined(RNLLAMA_ANDROID_ENABLE_LOGGING)
|
92
|
+
android_print();
|
93
|
+
#else
|
94
|
+
FILE * fcur = file;
|
95
|
+
if (!fcur) {
|
96
|
+
// stderr displays DBG messages only when their verbosity level is not higher than the threshold
|
97
|
+
// these messages will still be logged to a file
|
98
|
+
if (level == LM_GGML_LOG_LEVEL_DEBUG && common_log_verbosity_thold < LOG_DEFAULT_DEBUG) {
|
99
|
+
return;
|
100
|
+
}
|
101
|
+
|
102
|
+
fcur = stdout;
|
103
|
+
|
104
|
+
if (level != LM_GGML_LOG_LEVEL_NONE) {
|
105
|
+
fcur = stderr;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
if (level != LM_GGML_LOG_LEVEL_NONE && level != LM_GGML_LOG_LEVEL_CONT && prefix) {
|
110
|
+
if (timestamp) {
|
111
|
+
// [M.s.ms.us]
|
112
|
+
fprintf(fcur, "%s%d.%02d.%03d.%03d%s ",
|
113
|
+
g_col[COMMON_LOG_COL_BLUE],
|
114
|
+
(int) (timestamp / 1000000 / 60),
|
115
|
+
(int) (timestamp / 1000000 % 60),
|
116
|
+
(int) (timestamp / 1000 % 1000),
|
117
|
+
(int) (timestamp % 1000),
|
118
|
+
g_col[COMMON_LOG_COL_DEFAULT]);
|
119
|
+
}
|
120
|
+
|
121
|
+
switch (level) {
|
122
|
+
case LM_GGML_LOG_LEVEL_INFO: fprintf(fcur, "%sI %s", g_col[COMMON_LOG_COL_GREEN], g_col[COMMON_LOG_COL_DEFAULT]); break;
|
123
|
+
case LM_GGML_LOG_LEVEL_WARN: fprintf(fcur, "%sW %s", g_col[COMMON_LOG_COL_MAGENTA], "" ); break;
|
124
|
+
case LM_GGML_LOG_LEVEL_ERROR: fprintf(fcur, "%sE %s", g_col[COMMON_LOG_COL_RED], "" ); break;
|
125
|
+
case LM_GGML_LOG_LEVEL_DEBUG: fprintf(fcur, "%sD %s", g_col[COMMON_LOG_COL_YELLOW], "" ); break;
|
126
|
+
default:
|
127
|
+
break;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
fprintf(fcur, "%s", msg.data());
|
132
|
+
|
133
|
+
if (level == LM_GGML_LOG_LEVEL_WARN || level == LM_GGML_LOG_LEVEL_ERROR || level == LM_GGML_LOG_LEVEL_DEBUG) {
|
134
|
+
fprintf(fcur, "%s", g_col[COMMON_LOG_COL_DEFAULT]);
|
135
|
+
}
|
136
|
+
|
137
|
+
fflush(fcur);
|
138
|
+
#endif
|
139
|
+
}
|
140
|
+
};
|
141
|
+
|
142
|
+
struct common_log {
|
143
|
+
// default capacity - will be expanded if needed
|
144
|
+
common_log() : common_log(256) {}
|
145
|
+
|
146
|
+
common_log(size_t capacity) {
|
147
|
+
file = nullptr;
|
148
|
+
prefix = false;
|
149
|
+
timestamps = false;
|
150
|
+
running = false;
|
151
|
+
t_start = t_us();
|
152
|
+
|
153
|
+
// initial message size - will be expanded if longer messages arrive
|
154
|
+
entries.resize(capacity);
|
155
|
+
for (auto & entry : entries) {
|
156
|
+
entry.msg.resize(256);
|
157
|
+
}
|
158
|
+
|
159
|
+
head = 0;
|
160
|
+
tail = 0;
|
161
|
+
|
162
|
+
resume();
|
163
|
+
}
|
164
|
+
|
165
|
+
~common_log() {
|
166
|
+
pause();
|
167
|
+
if (file) {
|
168
|
+
fclose(file);
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
private:
|
173
|
+
std::mutex mtx;
|
174
|
+
std::thread thrd;
|
175
|
+
std::condition_variable cv;
|
176
|
+
|
177
|
+
FILE * file;
|
178
|
+
|
179
|
+
bool prefix;
|
180
|
+
bool timestamps;
|
181
|
+
bool running;
|
182
|
+
|
183
|
+
int64_t t_start;
|
184
|
+
|
185
|
+
// ring buffer of entries
|
186
|
+
std::vector<common_log_entry> entries;
|
187
|
+
size_t head;
|
188
|
+
size_t tail;
|
189
|
+
|
190
|
+
// worker thread copies into this
|
191
|
+
common_log_entry cur;
|
192
|
+
|
193
|
+
public:
|
194
|
+
void add(enum lm_ggml_log_level level, const char * fmt, va_list args) {
|
195
|
+
std::lock_guard<std::mutex> lock(mtx);
|
196
|
+
|
197
|
+
if (!running) {
|
198
|
+
// discard messages while the worker thread is paused
|
199
|
+
return;
|
200
|
+
}
|
201
|
+
|
202
|
+
auto & entry = entries[tail];
|
203
|
+
|
204
|
+
{
|
205
|
+
// cannot use args twice, so make a copy in case we need to expand the buffer
|
206
|
+
va_list args_copy;
|
207
|
+
va_copy(args_copy, args);
|
208
|
+
|
209
|
+
#if 1
|
210
|
+
const size_t n = vsnprintf(entry.msg.data(), entry.msg.size(), fmt, args);
|
211
|
+
if (n >= entry.msg.size()) {
|
212
|
+
entry.msg.resize(n + 1);
|
213
|
+
vsnprintf(entry.msg.data(), entry.msg.size(), fmt, args_copy);
|
214
|
+
}
|
215
|
+
#else
|
216
|
+
// hack for bolding arguments
|
217
|
+
|
218
|
+
std::stringstream ss;
|
219
|
+
for (int i = 0; fmt[i] != 0; i++) {
|
220
|
+
if (fmt[i] == '%') {
|
221
|
+
ss << LOG_COL_BOLD;
|
222
|
+
while (fmt[i] != ' ' && fmt[i] != ')' && fmt[i] != ']' && fmt[i] != 0) ss << fmt[i++];
|
223
|
+
ss << LOG_COL_DEFAULT;
|
224
|
+
if (fmt[i] == 0) break;
|
225
|
+
}
|
226
|
+
ss << fmt[i];
|
227
|
+
}
|
228
|
+
const size_t n = vsnprintf(entry.msg.data(), entry.msg.size(), ss.str().c_str(), args);
|
229
|
+
if (n >= entry.msg.size()) {
|
230
|
+
entry.msg.resize(n + 1);
|
231
|
+
vsnprintf(entry.msg.data(), entry.msg.size(), ss.str().c_str(), args_copy);
|
232
|
+
}
|
233
|
+
#endif
|
234
|
+
va_end(args_copy);
|
235
|
+
}
|
236
|
+
|
237
|
+
entry.level = level;
|
238
|
+
entry.prefix = prefix;
|
239
|
+
entry.timestamp = 0;
|
240
|
+
if (timestamps) {
|
241
|
+
entry.timestamp = t_us() - t_start;
|
242
|
+
}
|
243
|
+
entry.is_end = false;
|
244
|
+
|
245
|
+
tail = (tail + 1) % entries.size();
|
246
|
+
if (tail == head) {
|
247
|
+
// expand the buffer
|
248
|
+
std::vector<common_log_entry> new_entries(2*entries.size());
|
249
|
+
|
250
|
+
size_t new_tail = 0;
|
251
|
+
|
252
|
+
do {
|
253
|
+
new_entries[new_tail] = std::move(entries[head]);
|
254
|
+
|
255
|
+
head = (head + 1) % entries.size();
|
256
|
+
new_tail = (new_tail + 1);
|
257
|
+
} while (head != tail);
|
258
|
+
|
259
|
+
head = 0;
|
260
|
+
tail = new_tail;
|
261
|
+
|
262
|
+
for (size_t i = tail; i < new_entries.size(); i++) {
|
263
|
+
new_entries[i].msg.resize(256);
|
264
|
+
}
|
265
|
+
|
266
|
+
entries = std::move(new_entries);
|
267
|
+
}
|
268
|
+
|
269
|
+
cv.notify_one();
|
270
|
+
}
|
271
|
+
|
272
|
+
void resume() {
|
273
|
+
std::lock_guard<std::mutex> lock(mtx);
|
274
|
+
|
275
|
+
if (running) {
|
276
|
+
return;
|
277
|
+
}
|
278
|
+
|
279
|
+
running = true;
|
280
|
+
|
281
|
+
thrd = std::thread([this]() {
|
282
|
+
while (true) {
|
283
|
+
{
|
284
|
+
std::unique_lock<std::mutex> lock(mtx);
|
285
|
+
cv.wait(lock, [this]() { return head != tail; });
|
286
|
+
|
287
|
+
cur = entries[head];
|
288
|
+
|
289
|
+
head = (head + 1) % entries.size();
|
290
|
+
}
|
291
|
+
|
292
|
+
if (cur.is_end) {
|
293
|
+
break;
|
294
|
+
}
|
295
|
+
|
296
|
+
cur.print(); // stdout and stderr
|
297
|
+
|
298
|
+
if (file) {
|
299
|
+
cur.print(file);
|
300
|
+
}
|
301
|
+
}
|
302
|
+
});
|
303
|
+
}
|
304
|
+
|
305
|
+
void pause() {
|
306
|
+
{
|
307
|
+
std::lock_guard<std::mutex> lock(mtx);
|
308
|
+
|
309
|
+
if (!running) {
|
310
|
+
return;
|
311
|
+
}
|
312
|
+
|
313
|
+
running = false;
|
314
|
+
|
315
|
+
// push an entry to signal the worker thread to stop
|
316
|
+
{
|
317
|
+
auto & entry = entries[tail];
|
318
|
+
entry.is_end = true;
|
319
|
+
|
320
|
+
tail = (tail + 1) % entries.size();
|
321
|
+
}
|
322
|
+
|
323
|
+
cv.notify_one();
|
324
|
+
}
|
325
|
+
|
326
|
+
thrd.join();
|
327
|
+
}
|
328
|
+
|
329
|
+
void set_file(const char * path) {
|
330
|
+
pause();
|
331
|
+
|
332
|
+
if (file) {
|
333
|
+
fclose(file);
|
334
|
+
}
|
335
|
+
|
336
|
+
if (path) {
|
337
|
+
file = fopen(path, "w");
|
338
|
+
} else {
|
339
|
+
file = nullptr;
|
340
|
+
}
|
341
|
+
|
342
|
+
resume();
|
343
|
+
}
|
344
|
+
|
345
|
+
void set_colors(bool colors) {
|
346
|
+
pause();
|
347
|
+
|
348
|
+
if (colors) {
|
349
|
+
g_col[COMMON_LOG_COL_DEFAULT] = LOG_COL_DEFAULT;
|
350
|
+
g_col[COMMON_LOG_COL_BOLD] = LOG_COL_BOLD;
|
351
|
+
g_col[COMMON_LOG_COL_RED] = LOG_COL_RED;
|
352
|
+
g_col[COMMON_LOG_COL_GREEN] = LOG_COL_GREEN;
|
353
|
+
g_col[COMMON_LOG_COL_YELLOW] = LOG_COL_YELLOW;
|
354
|
+
g_col[COMMON_LOG_COL_BLUE] = LOG_COL_BLUE;
|
355
|
+
g_col[COMMON_LOG_COL_MAGENTA] = LOG_COL_MAGENTA;
|
356
|
+
g_col[COMMON_LOG_COL_CYAN] = LOG_COL_CYAN;
|
357
|
+
g_col[COMMON_LOG_COL_WHITE] = LOG_COL_WHITE;
|
358
|
+
} else {
|
359
|
+
for (size_t i = 0; i < g_col.size(); i++) {
|
360
|
+
g_col[i] = "";
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
resume();
|
365
|
+
}
|
366
|
+
|
367
|
+
void set_prefix(bool prefix) {
|
368
|
+
std::lock_guard<std::mutex> lock(mtx);
|
369
|
+
|
370
|
+
this->prefix = prefix;
|
371
|
+
}
|
372
|
+
|
373
|
+
void set_timestamps(bool timestamps) {
|
374
|
+
std::lock_guard<std::mutex> lock(mtx);
|
375
|
+
|
376
|
+
this->timestamps = timestamps;
|
377
|
+
}
|
378
|
+
};
|
379
|
+
|
380
|
+
//
|
381
|
+
// public API
|
382
|
+
//
|
383
|
+
|
384
|
+
struct common_log * common_log_init() {
|
385
|
+
return new common_log;
|
386
|
+
}
|
387
|
+
|
388
|
+
struct common_log * common_log_main() {
|
389
|
+
static struct common_log log;
|
390
|
+
|
391
|
+
return &log;
|
392
|
+
}
|
393
|
+
|
394
|
+
void common_log_pause(struct common_log * log) {
|
395
|
+
log->pause();
|
396
|
+
}
|
397
|
+
|
398
|
+
void common_log_resume(struct common_log * log) {
|
399
|
+
log->resume();
|
400
|
+
}
|
401
|
+
|
402
|
+
void common_log_free(struct common_log * log) {
|
403
|
+
delete log;
|
404
|
+
}
|
405
|
+
|
406
|
+
void common_log_add(struct common_log * log, enum lm_ggml_log_level level, const char * fmt, ...) {
|
407
|
+
va_list args;
|
408
|
+
va_start(args, fmt);
|
409
|
+
log->add(level, fmt, args);
|
410
|
+
va_end(args);
|
411
|
+
}
|
412
|
+
|
413
|
+
void common_log_set_file(struct common_log * log, const char * file) {
|
414
|
+
log->set_file(file);
|
415
|
+
}
|
416
|
+
|
417
|
+
void common_log_set_colors(struct common_log * log, bool colors) {
|
418
|
+
log->set_colors(colors);
|
419
|
+
}
|
420
|
+
|
421
|
+
void common_log_set_prefix(struct common_log * log, bool prefix) {
|
422
|
+
log->set_prefix(prefix);
|
423
|
+
}
|
424
|
+
|
425
|
+
void common_log_set_timestamps(struct common_log * log, bool timestamps) {
|
426
|
+
log->set_timestamps(timestamps);
|
427
|
+
}
|