feat: auto-update settings
This commit is contained in:
parent
ac07317119
commit
38aed01ac1
25
dialog.jai
25
dialog.jai
@ -110,6 +110,8 @@ dialog_proc :: (hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
|||||||
trimmed_url := trim(url_utf8);
|
trimmed_url := trim(url_utf8);
|
||||||
if trimmed_url {
|
if trimmed_url {
|
||||||
mode: string;
|
mode: string;
|
||||||
|
port := ifx state.is_test_mode then 10899 else 10801;
|
||||||
|
update_interval := 3600;
|
||||||
config_filename := ifx state.is_test_mode then "config_test.json" else "config.json";
|
config_filename := ifx state.is_test_mode then "config_test.json" else "config.json";
|
||||||
config_data, read_ok := read_entire_file(config_filename);
|
config_data, read_ok := read_entire_file(config_filename);
|
||||||
if read_ok {
|
if read_ok {
|
||||||
@ -119,13 +121,23 @@ dialog_proc :: (hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
|||||||
} else {
|
} else {
|
||||||
mode = copy_string("system_proxy");
|
mode = copy_string("system_proxy");
|
||||||
}
|
}
|
||||||
|
port_str := get_json_val_field(config_data, "\"_port\"");
|
||||||
|
if port_str {
|
||||||
|
val, ok := to_integer(port_str);
|
||||||
|
if ok port = xx val;
|
||||||
|
}
|
||||||
|
interval_str := get_json_val_field(config_data, "\"_update_interval\"");
|
||||||
|
if interval_str {
|
||||||
|
val, ok := to_integer(interval_str);
|
||||||
|
if ok update_interval = xx val;
|
||||||
|
}
|
||||||
free(config_data);
|
free(config_data);
|
||||||
} else {
|
} else {
|
||||||
mode = copy_string("system_proxy");
|
mode = copy_string("system_proxy");
|
||||||
}
|
}
|
||||||
defer free(mode);
|
defer free(mode);
|
||||||
|
|
||||||
minimal_json := tprint("{\n \"_url\": \"%\",\n \"_mode\": \"%\",\n \"inbounds\": [],\n \"outbounds\": []\n}", trimmed_url, mode);
|
minimal_json := tprint("{\n \"_url\": \"%\",\n \"_mode\": \"%\",\n \"_port\": %,\n \"_update_interval\": %,\n \"inbounds\": [],\n \"outbounds\": []\n}", trimmed_url, mode, port, update_interval);
|
||||||
write_entire_file(config_filename, minimal_json);
|
write_entire_file(config_filename, minimal_json);
|
||||||
state.url_saved = true;
|
state.url_saved = true;
|
||||||
}
|
}
|
||||||
@ -342,6 +354,7 @@ show_config_port_dialog :: (parent_hwnd: HWND, is_test_mode := false) -> bool {
|
|||||||
config_data, read_ok := read_entire_file(config_filename);
|
config_data, read_ok := read_entire_file(config_filename);
|
||||||
url := "";
|
url := "";
|
||||||
mode := "system_proxy";
|
mode := "system_proxy";
|
||||||
|
update_interval := 3600;
|
||||||
if read_ok {
|
if read_ok {
|
||||||
extracted_url := get_json_string_field(config_data, "\"_url\"");
|
extracted_url := get_json_string_field(config_data, "\"_url\"");
|
||||||
if extracted_url url = copy_string(extracted_url);
|
if extracted_url url = copy_string(extracted_url);
|
||||||
@ -353,12 +366,18 @@ show_config_port_dialog :: (parent_hwnd: HWND, is_test_mode := false) -> bool {
|
|||||||
mode = copy_string("system_proxy");
|
mode = copy_string("system_proxy");
|
||||||
}
|
}
|
||||||
|
|
||||||
updated := set_json_metadata(config_data, url, mode, port);
|
interval_str := get_json_val_field(config_data, "\"_update_interval\"");
|
||||||
|
if interval_str {
|
||||||
|
val, ok := to_integer(interval_str);
|
||||||
|
if ok update_interval = xx val;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated := set_json_metadata(config_data, url, mode, port, update_interval);
|
||||||
write_entire_file(config_filename, updated);
|
write_entire_file(config_filename, updated);
|
||||||
free(config_data);
|
free(config_data);
|
||||||
free(updated);
|
free(updated);
|
||||||
} else {
|
} else {
|
||||||
minimal_json := tprint("{\n \"_url\": \"\",\n \"_mode\": \"system_proxy\",\n \"_port\": %,\n \"inbounds\": [],\n \"outbounds\": []\n}", port);
|
minimal_json := tprint("{\n \"_url\": \"\",\n \"_mode\": \"system_proxy\",\n \"_port\": %,\n \"_update_interval\": %,\n \"inbounds\": [],\n \"outbounds\": []\n}", port, update_interval);
|
||||||
write_entire_file(config_filename, minimal_json);
|
write_entire_file(config_filename, minimal_json);
|
||||||
}
|
}
|
||||||
if url free(url);
|
if url free(url);
|
||||||
|
|||||||
81
main.jai
81
main.jai
@ -602,6 +602,18 @@ show_context_menu :: (app: *App_State) {
|
|||||||
AppendMenuW(hMenu, MF_STRING, CMD_SET_PORT, utf8_to_wide("Configure Port..."));
|
AppendMenuW(hMenu, MF_STRING, CMD_SET_PORT, utf8_to_wide("Configure Port..."));
|
||||||
AppendMenuW(hMenu, MF_STRING, CMD_UPDATE_NOW, utf8_to_wide("Update Config Now"));
|
AppendMenuW(hMenu, MF_STRING, CMD_UPDATE_NOW, utf8_to_wide("Update Config Now"));
|
||||||
|
|
||||||
|
hUpdateMenu := CreatePopupMenu();
|
||||||
|
current_interval := app.updater_data.update_interval_seconds;
|
||||||
|
AppendMenuW(hUpdateMenu, MF_STRING | (ifx current_interval == 0 then MF_CHECKED else 0), CMD_UPDATE_NEVER, utf8_to_wide("Never"));
|
||||||
|
AppendMenuW(hUpdateMenu, MF_STRING | (ifx current_interval == 1800 then MF_CHECKED else 0), CMD_UPDATE_30M, utf8_to_wide("30 minutes"));
|
||||||
|
AppendMenuW(hUpdateMenu, MF_STRING | (ifx current_interval == 3600 then MF_CHECKED else 0), CMD_UPDATE_1H, utf8_to_wide("1 hour"));
|
||||||
|
AppendMenuW(hUpdateMenu, MF_STRING | (ifx current_interval == 21600 then MF_CHECKED else 0), CMD_UPDATE_6H, utf8_to_wide("6 hours"));
|
||||||
|
AppendMenuW(hUpdateMenu, MF_STRING | (ifx current_interval == 43200 then MF_CHECKED else 0), CMD_UPDATE_12H, utf8_to_wide("12 hours"));
|
||||||
|
AppendMenuW(hUpdateMenu, MF_STRING | (ifx current_interval == 86400 then MF_CHECKED else 0), CMD_UPDATE_DAILY, utf8_to_wide("Daily"));
|
||||||
|
AppendMenuW(hUpdateMenu, MF_STRING | (ifx current_interval == 259200 then MF_CHECKED else 0), CMD_UPDATE_3D, utf8_to_wide("3 days"));
|
||||||
|
AppendMenuW(hUpdateMenu, MF_STRING | (ifx current_interval == 604800 then MF_CHECKED else 0), CMD_UPDATE_WEEKLY, utf8_to_wide("weekly"));
|
||||||
|
AppendMenuW(hMenu, MF_POPUP, cast(s64) hUpdateMenu, utf8_to_wide("Config Auto-Update"));
|
||||||
|
|
||||||
AppendMenuW(hMenu, MF_SEPARATOR, 0, null);
|
AppendMenuW(hMenu, MF_SEPARATOR, 0, null);
|
||||||
|
|
||||||
proxy_flags := MF_STRING;
|
proxy_flags := MF_STRING;
|
||||||
@ -685,7 +697,7 @@ show_context_menu :: (app: *App_State) {
|
|||||||
config_data, read_ok := read_entire_file(config_filename);
|
config_data, read_ok := read_entire_file(config_filename);
|
||||||
if read_ok {
|
if read_ok {
|
||||||
url := get_json_string_field(config_data, "\"_url\"");
|
url := get_json_string_field(config_data, "\"_url\"");
|
||||||
updated := set_json_metadata(config_data, url, "proxy", app.port);
|
updated := set_json_metadata(config_data, url, "proxy", app.port, app.updater_data.update_interval_seconds);
|
||||||
write_entire_file(config_filename, updated);
|
write_entire_file(config_filename, updated);
|
||||||
free(config_data);
|
free(config_data);
|
||||||
free(updated);
|
free(updated);
|
||||||
@ -710,7 +722,7 @@ show_context_menu :: (app: *App_State) {
|
|||||||
config_data, read_ok := read_entire_file(config_filename);
|
config_data, read_ok := read_entire_file(config_filename);
|
||||||
if read_ok {
|
if read_ok {
|
||||||
url := get_json_string_field(config_data, "\"_url\"");
|
url := get_json_string_field(config_data, "\"_url\"");
|
||||||
updated := set_json_metadata(config_data, url, "system_proxy", app.port);
|
updated := set_json_metadata(config_data, url, "system_proxy", app.port, app.updater_data.update_interval_seconds);
|
||||||
write_entire_file(config_filename, updated);
|
write_entire_file(config_filename, updated);
|
||||||
free(config_data);
|
free(config_data);
|
||||||
free(updated);
|
free(updated);
|
||||||
@ -738,6 +750,38 @@ show_context_menu :: (app: *App_State) {
|
|||||||
MessageBoxW(app.hwnd, utf8_to_wide("Failed to update Windows registry autostart configuration."), utf8_to_wide("Sing-box Tray"), MB_ICONERROR);
|
MessageBoxW(app.hwnd, utf8_to_wide("Failed to update Windows registry autostart configuration."), utf8_to_wide("Sing-box Tray"), MB_ICONERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case CMD_UPDATE_NEVER; {
|
||||||
|
save_update_interval(app, 0);
|
||||||
|
log_print("Auto-update interval set to: Never\n");
|
||||||
|
}
|
||||||
|
case CMD_UPDATE_30M; {
|
||||||
|
save_update_interval(app, 1800);
|
||||||
|
log_print("Auto-update interval set to: 30 minutes\n");
|
||||||
|
}
|
||||||
|
case CMD_UPDATE_1H; {
|
||||||
|
save_update_interval(app, 3600);
|
||||||
|
log_print("Auto-update interval set to: 1 hour\n");
|
||||||
|
}
|
||||||
|
case CMD_UPDATE_6H; {
|
||||||
|
save_update_interval(app, 21600);
|
||||||
|
log_print("Auto-update interval set to: 6 hours\n");
|
||||||
|
}
|
||||||
|
case CMD_UPDATE_12H; {
|
||||||
|
save_update_interval(app, 43200);
|
||||||
|
log_print("Auto-update interval set to: 12 hours\n");
|
||||||
|
}
|
||||||
|
case CMD_UPDATE_DAILY; {
|
||||||
|
save_update_interval(app, 86400);
|
||||||
|
log_print("Auto-update interval set to: Daily\n");
|
||||||
|
}
|
||||||
|
case CMD_UPDATE_3D; {
|
||||||
|
save_update_interval(app, 259200);
|
||||||
|
log_print("Auto-update interval set to: 3 days\n");
|
||||||
|
}
|
||||||
|
case CMD_UPDATE_WEEKLY; {
|
||||||
|
save_update_interval(app, 604800);
|
||||||
|
log_print("Auto-update interval set to: weekly\n");
|
||||||
|
}
|
||||||
case CMD_EXIT; {
|
case CMD_EXIT; {
|
||||||
DestroyWindow(app.hwnd);
|
DestroyWindow(app.hwnd);
|
||||||
}
|
}
|
||||||
@ -816,6 +860,25 @@ load_stock_icon :: (siid: s32) -> HICON {
|
|||||||
|
|
||||||
global_is_test_mode: bool = false;
|
global_is_test_mode: bool = false;
|
||||||
|
|
||||||
|
save_update_interval :: (app: *App_State, interval: s32) {
|
||||||
|
app.updater_data.update_interval_seconds = interval;
|
||||||
|
|
||||||
|
config_filename := ifx app.is_test_mode then "config_test.json" else "config.json";
|
||||||
|
config_data, read_ok := read_entire_file(config_filename);
|
||||||
|
if read_ok {
|
||||||
|
url := get_json_string_field(config_data, "\"_url\"");
|
||||||
|
mode := get_json_string_field(config_data, "\"_mode\"");
|
||||||
|
|
||||||
|
mode_val := ifx mode then mode else "system_proxy";
|
||||||
|
|
||||||
|
updated := set_json_metadata(config_data, url, mode_val, app.port, interval);
|
||||||
|
write_entire_file(config_filename, updated);
|
||||||
|
|
||||||
|
free(config_data);
|
||||||
|
free(updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
main :: () {
|
main :: () {
|
||||||
args := get_command_line_arguments();
|
args := get_command_line_arguments();
|
||||||
is_test := false;
|
is_test := false;
|
||||||
@ -891,7 +954,9 @@ main :: () {
|
|||||||
|
|
||||||
config_filename := ifx app_state.is_test_mode then "config_test.json" else "config.json";
|
config_filename := ifx app_state.is_test_mode then "config_test.json" else "config.json";
|
||||||
|
|
||||||
// Load persisted mode and port from config file
|
app_state.updater_data.update_interval_seconds = 3600; // default
|
||||||
|
|
||||||
|
// Load persisted mode, port, and update interval from config file
|
||||||
config_data, read_ok := read_entire_file(config_filename);
|
config_data, read_ok := read_entire_file(config_filename);
|
||||||
if read_ok {
|
if read_ok {
|
||||||
extracted_mode := get_json_string_field(config_data, "\"_mode\"");
|
extracted_mode := get_json_string_field(config_data, "\"_mode\"");
|
||||||
@ -899,6 +964,15 @@ main :: () {
|
|||||||
app_state.use_system_proxy = false;
|
app_state.use_system_proxy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interval_str := get_json_val_field(config_data, "\"_update_interval\"");
|
||||||
|
if interval_str {
|
||||||
|
val, ok := to_integer(interval_str);
|
||||||
|
if ok {
|
||||||
|
app_state.updater_data.update_interval_seconds = xx val;
|
||||||
|
log_print("Loaded update interval: % seconds\n", app_state.updater_data.update_interval_seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if app_state.is_test_mode {
|
if app_state.is_test_mode {
|
||||||
app_state.port = 10899; // force test port in test mode
|
app_state.port = 10899; // force test port in test mode
|
||||||
log_info("Loaded config from %. Test mode: forcing port to %.\n", config_filename, app_state.port);
|
log_info("Loaded config from %. Test mode: forcing port to %.\n", config_filename, app_state.port);
|
||||||
@ -946,7 +1020,6 @@ main :: () {
|
|||||||
defer KillTimer(hwnd, TIMER_PROCESS_CHECK);
|
defer KillTimer(hwnd, TIMER_PROCESS_CHECK);
|
||||||
|
|
||||||
app_state.updater_data.hwnd = hwnd;
|
app_state.updater_data.hwnd = hwnd;
|
||||||
app_state.updater_data.update_interval_seconds = 3600;
|
|
||||||
app_state.updater_data.stop_event = CreateEventW(null, TRUE, FALSE, null);
|
app_state.updater_data.stop_event = CreateEventW(null, TRUE, FALSE, null);
|
||||||
app_state.updater_data.is_test_mode = app_state.is_test_mode;
|
app_state.updater_data.is_test_mode = app_state.is_test_mode;
|
||||||
|
|
||||||
|
|||||||
33
updater.jai
33
updater.jai
@ -110,6 +110,15 @@ perform_update :: (is_test_mode := false) -> changed: bool, success: bool, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_interval := 3600;
|
||||||
|
interval_str := get_json_val_field(config_data, "\"_update_interval\"");
|
||||||
|
if interval_str {
|
||||||
|
val, parse_ok, remainder := to_integer(interval_str);
|
||||||
|
if parse_ok {
|
||||||
|
update_interval = xx val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
downloaded, success, err_msg := download_url(url);
|
downloaded, success, err_msg := download_url(url);
|
||||||
if !success return false, false, err_msg;
|
if !success return false, false, err_msg;
|
||||||
defer free(downloaded);
|
defer free(downloaded);
|
||||||
@ -117,7 +126,7 @@ perform_update :: (is_test_mode := false) -> changed: bool, success: bool, error
|
|||||||
modified := modify_config_inbounds(downloaded, port);
|
modified := modify_config_inbounds(downloaded, port);
|
||||||
defer free(modified);
|
defer free(modified);
|
||||||
|
|
||||||
final_config := set_json_metadata(modified, url, mode, port);
|
final_config := set_json_metadata(modified, url, mode, port, update_interval);
|
||||||
defer free(final_config);
|
defer free(final_config);
|
||||||
|
|
||||||
if config_data == final_config {
|
if config_data == final_config {
|
||||||
@ -137,14 +146,23 @@ updater_thread_proc :: (thread: *Thread) -> s64 {
|
|||||||
data := cast(*Updater_Thread_Data) thread.data;
|
data := cast(*Updater_Thread_Data) thread.data;
|
||||||
if !data return 1;
|
if !data return 1;
|
||||||
|
|
||||||
|
elapsed_seconds := 0;
|
||||||
while true {
|
while true {
|
||||||
// Wait on the stop event for the specified interval.
|
status := WaitForSingleObject(data.stop_event, 1000);
|
||||||
// If the stop event is signaled, wake up immediately and terminate.
|
|
||||||
status := WaitForSingleObject(data.stop_event, cast(DWORD) (data.update_interval_seconds * 1000));
|
|
||||||
if status == WAIT_OBJECT_0 {
|
if status == WAIT_OBJECT_0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interval := data.update_interval_seconds;
|
||||||
|
if interval <= 0 {
|
||||||
|
elapsed_seconds = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed_seconds += 1;
|
||||||
|
if elapsed_seconds >= interval {
|
||||||
|
elapsed_seconds = 0;
|
||||||
|
|
||||||
log_debug("Background update: Starting automatic config check...\n");
|
log_debug("Background update: Starting automatic config check...\n");
|
||||||
changed, success, err_msg := perform_update(data.is_test_mode);
|
changed, success, err_msg := perform_update(data.is_test_mode);
|
||||||
if success {
|
if success {
|
||||||
@ -160,6 +178,7 @@ updater_thread_proc :: (thread: *Thread) -> s64 {
|
|||||||
log_error("Background update failed: %\n", err_msg);
|
log_error("Background update failed: %\n", err_msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -277,7 +296,7 @@ get_json_val_field :: (json: string, field: string) -> string {
|
|||||||
return trim(slice(json, val_start, val_end - val_start + 1));
|
return trim(slice(json, val_start, val_end - val_start + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
set_json_metadata :: (json: string, url: string, mode: string, port: int) -> string {
|
set_json_metadata :: (json: string, url: string, mode: string, port: int, update_interval: int) -> string {
|
||||||
lines := split(json, "\n");
|
lines := split(json, "\n");
|
||||||
defer array_free(lines);
|
defer array_free(lines);
|
||||||
|
|
||||||
@ -289,12 +308,13 @@ set_json_metadata :: (json: string, url: string, mode: string, port: int) -> str
|
|||||||
if find_index_from_left(trimmed, "\"_url\"") != -1 continue;
|
if find_index_from_left(trimmed, "\"_url\"") != -1 continue;
|
||||||
if find_index_from_left(trimmed, "\"_mode\"") != -1 continue;
|
if find_index_from_left(trimmed, "\"_mode\"") != -1 continue;
|
||||||
if find_index_from_left(trimmed, "\"_port\"") != -1 continue;
|
if find_index_from_left(trimmed, "\"_port\"") != -1 continue;
|
||||||
|
if find_index_from_left(trimmed, "\"_update_interval\"") != -1 continue;
|
||||||
|
|
||||||
append(*builder, it);
|
append(*builder, it);
|
||||||
append(*builder, "\n");
|
append(*builder, "\n");
|
||||||
|
|
||||||
if !inserted && find_index_from_left(trimmed, "{") != -1 {
|
if !inserted && find_index_from_left(trimmed, "{") != -1 {
|
||||||
append(*builder, tprint(" \"_url\": \"%\",\n \"_mode\": \"%\",\n \"_port\": %,\n", url, mode, port));
|
append(*builder, tprint(" \"_url\": \"%\",\n \"_mode\": \"%\",\n \"_port\": %,\n \"_update_interval\": %,\n", url, mode, port, update_interval));
|
||||||
inserted = true;
|
inserted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,6 +332,7 @@ strip_json_metadata :: (json: string) -> string {
|
|||||||
if find_index_from_left(trimmed, "\"_url\"") != -1 continue;
|
if find_index_from_left(trimmed, "\"_url\"") != -1 continue;
|
||||||
if find_index_from_left(trimmed, "\"_mode\"") != -1 continue;
|
if find_index_from_left(trimmed, "\"_mode\"") != -1 continue;
|
||||||
if find_index_from_left(trimmed, "\"_port\"") != -1 continue;
|
if find_index_from_left(trimmed, "\"_port\"") != -1 continue;
|
||||||
|
if find_index_from_left(trimmed, "\"_update_interval\"") != -1 continue;
|
||||||
|
|
||||||
append(*builder, it);
|
append(*builder, it);
|
||||||
append(*builder, "\n");
|
append(*builder, "\n");
|
||||||
|
|||||||
10
win32.jai
10
win32.jai
@ -46,7 +46,9 @@ MF_GRAYED : u32 : 0x00000001;
|
|||||||
MF_DISABLED : u32 : 0x00000002;
|
MF_DISABLED : u32 : 0x00000002;
|
||||||
MF_SEPARATOR : u32 : 0x00000800;
|
MF_SEPARATOR : u32 : 0x00000800;
|
||||||
MF_CHECKED : u32 : 0x00000008;
|
MF_CHECKED : u32 : 0x00000008;
|
||||||
|
MF_POPUP : u32 : 0x00000010;
|
||||||
|
|
||||||
|
// NIM constants
|
||||||
NIM_ADD : u32 : 0x00000000;
|
NIM_ADD : u32 : 0x00000000;
|
||||||
NIM_MODIFY : u32 : 0x00000001;
|
NIM_MODIFY : u32 : 0x00000001;
|
||||||
NIM_DELETE : u32 : 0x00000002;
|
NIM_DELETE : u32 : 0x00000002;
|
||||||
@ -83,6 +85,14 @@ CMD_MODE_PROXY :: 1006;
|
|||||||
CMD_MODE_SYS_PROXY :: 1007;
|
CMD_MODE_SYS_PROXY :: 1007;
|
||||||
CMD_SET_PORT :: 1008;
|
CMD_SET_PORT :: 1008;
|
||||||
CMD_TOGGLE_AUTOSTART:: 1009;
|
CMD_TOGGLE_AUTOSTART:: 1009;
|
||||||
|
CMD_UPDATE_NEVER :: 1010;
|
||||||
|
CMD_UPDATE_30M :: 1011;
|
||||||
|
CMD_UPDATE_1H :: 1012;
|
||||||
|
CMD_UPDATE_6H :: 1013;
|
||||||
|
CMD_UPDATE_12H :: 1014;
|
||||||
|
CMD_UPDATE_DAILY :: 1015;
|
||||||
|
CMD_UPDATE_3D :: 1016;
|
||||||
|
CMD_UPDATE_WEEKLY :: 1017;
|
||||||
|
|
||||||
// Boolean constants
|
// Boolean constants
|
||||||
FALSE :: 0;
|
FALSE :: 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user