|
|
9ae3a8 |
From f0e4ec43a0a3af6f1e385fae17527ed76cdb00e4 Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: John Snow <jsnow@redhat.com>
|
|
|
9ae3a8 |
Date: Mon, 23 Nov 2015 17:38:32 +0100
|
|
|
9ae3a8 |
Subject: [PATCH 13/27] qemu-io: Move remaining helpers from cmd.c
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: John Snow <jsnow@redhat.com>
|
|
|
9ae3a8 |
Message-id: <1448300320-7772-14-git-send-email-jsnow@redhat.com>
|
|
|
9ae3a8 |
Patchwork-id: 68437
|
|
|
9ae3a8 |
O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 13/21] qemu-io: Move remaining helpers from cmd.c
|
|
|
9ae3a8 |
Bugzilla: 1272523
|
|
|
9ae3a8 |
RH-Acked-by: Thomas Huth <thuth@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Max Reitz <mreitz@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
From: Kevin Wolf <kwolf@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
9ae3a8 |
(cherry picked from commit 0b613881ae8fc59359b3d91e666fea6c9b1e731b)
|
|
|
9ae3a8 |
Signed-off-by: John Snow <jsnow@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
Makefile | 2 +-
|
|
|
9ae3a8 |
cmd.c | 139 ---------------------------------------------------------
|
|
|
9ae3a8 |
cmd.h | 14 ------
|
|
|
9ae3a8 |
qemu-io-cmds.c | 104 ++++++++++++++++++++++++++++++++++++++++++
|
|
|
9ae3a8 |
4 files changed, 105 insertions(+), 154 deletions(-)
|
|
|
9ae3a8 |
delete mode 100644 cmd.c
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/Makefile b/Makefile
|
|
|
9ae3a8 |
index f28ce29..f403057 100644
|
|
|
9ae3a8 |
--- a/Makefile
|
|
|
9ae3a8 |
+++ b/Makefile
|
|
|
9ae3a8 |
@@ -205,7 +205,7 @@ qemu-img.o: qemu-img-cmds.h
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
|
|
|
9ae3a8 |
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
|
|
|
9ae3a8 |
-qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a
|
|
|
9ae3a8 |
+qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o $(block-obj-y) libqemuutil.a libqemustub.a
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/cmd.c b/cmd.c
|
|
|
9ae3a8 |
deleted file mode 100644
|
|
|
9ae3a8 |
index 26d38a8..0000000
|
|
|
9ae3a8 |
--- a/cmd.c
|
|
|
9ae3a8 |
+++ /dev/null
|
|
|
9ae3a8 |
@@ -1,139 +0,0 @@
|
|
|
9ae3a8 |
-/*
|
|
|
9ae3a8 |
- * Copyright (c) 2003-2005 Silicon Graphics, Inc.
|
|
|
9ae3a8 |
- * All Rights Reserved.
|
|
|
9ae3a8 |
- *
|
|
|
9ae3a8 |
- * This program is free software; you can redistribute it and/or
|
|
|
9ae3a8 |
- * modify it under the terms of the GNU General Public License as
|
|
|
9ae3a8 |
- * published by the Free Software Foundation.
|
|
|
9ae3a8 |
- *
|
|
|
9ae3a8 |
- * This program is distributed in the hope that it would be useful,
|
|
|
9ae3a8 |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
9ae3a8 |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
9ae3a8 |
- * GNU General Public License for more details.
|
|
|
9ae3a8 |
- *
|
|
|
9ae3a8 |
- * You should have received a copy of the GNU General Public License
|
|
|
9ae3a8 |
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
9ae3a8 |
- */
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-#include <stdio.h>
|
|
|
9ae3a8 |
-#include <stdlib.h>
|
|
|
9ae3a8 |
-#include <string.h>
|
|
|
9ae3a8 |
-#include <ctype.h>
|
|
|
9ae3a8 |
-#include <errno.h>
|
|
|
9ae3a8 |
-#include <sys/time.h>
|
|
|
9ae3a8 |
-#include <getopt.h>
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-#include "cmd.h"
|
|
|
9ae3a8 |
-#include "block/aio.h"
|
|
|
9ae3a8 |
-#include "qemu/main-loop.h"
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-#define _(x) x /* not gettext support yet */
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-/* from libxcmd/command.c */
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-#define EXABYTES(x) ((long long)(x) << 60)
|
|
|
9ae3a8 |
-#define PETABYTES(x) ((long long)(x) << 50)
|
|
|
9ae3a8 |
-#define TERABYTES(x) ((long long)(x) << 40)
|
|
|
9ae3a8 |
-#define GIGABYTES(x) ((long long)(x) << 30)
|
|
|
9ae3a8 |
-#define MEGABYTES(x) ((long long)(x) << 20)
|
|
|
9ae3a8 |
-#define KILOBYTES(x) ((long long)(x) << 10)
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-#define TO_EXABYTES(x) ((x) / EXABYTES(1))
|
|
|
9ae3a8 |
-#define TO_PETABYTES(x) ((x) / PETABYTES(1))
|
|
|
9ae3a8 |
-#define TO_TERABYTES(x) ((x) / TERABYTES(1))
|
|
|
9ae3a8 |
-#define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
|
|
|
9ae3a8 |
-#define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
|
|
|
9ae3a8 |
-#define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-void
|
|
|
9ae3a8 |
-cvtstr(
|
|
|
9ae3a8 |
- double value,
|
|
|
9ae3a8 |
- char *str,
|
|
|
9ae3a8 |
- size_t size)
|
|
|
9ae3a8 |
-{
|
|
|
9ae3a8 |
- char *trim;
|
|
|
9ae3a8 |
- const char *suffix;
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
- if (value >= EXABYTES(1)) {
|
|
|
9ae3a8 |
- suffix = " EiB";
|
|
|
9ae3a8 |
- snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
|
|
|
9ae3a8 |
- } else if (value >= PETABYTES(1)) {
|
|
|
9ae3a8 |
- suffix = " PiB";
|
|
|
9ae3a8 |
- snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
|
|
|
9ae3a8 |
- } else if (value >= TERABYTES(1)) {
|
|
|
9ae3a8 |
- suffix = " TiB";
|
|
|
9ae3a8 |
- snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
|
|
|
9ae3a8 |
- } else if (value >= GIGABYTES(1)) {
|
|
|
9ae3a8 |
- suffix = " GiB";
|
|
|
9ae3a8 |
- snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
|
|
|
9ae3a8 |
- } else if (value >= MEGABYTES(1)) {
|
|
|
9ae3a8 |
- suffix = " MiB";
|
|
|
9ae3a8 |
- snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
|
|
|
9ae3a8 |
- } else if (value >= KILOBYTES(1)) {
|
|
|
9ae3a8 |
- suffix = " KiB";
|
|
|
9ae3a8 |
- snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
|
|
|
9ae3a8 |
- } else {
|
|
|
9ae3a8 |
- suffix = " bytes";
|
|
|
9ae3a8 |
- snprintf(str, size - 6, "%f", value);
|
|
|
9ae3a8 |
- }
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
- trim = strstr(str, ".000");
|
|
|
9ae3a8 |
- if (trim) {
|
|
|
9ae3a8 |
- strcpy(trim, suffix);
|
|
|
9ae3a8 |
- } else {
|
|
|
9ae3a8 |
- strcat(str, suffix);
|
|
|
9ae3a8 |
- }
|
|
|
9ae3a8 |
-}
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-struct timeval
|
|
|
9ae3a8 |
-tsub(struct timeval t1, struct timeval t2)
|
|
|
9ae3a8 |
-{
|
|
|
9ae3a8 |
- t1.tv_usec -= t2.tv_usec;
|
|
|
9ae3a8 |
- if (t1.tv_usec < 0) {
|
|
|
9ae3a8 |
- t1.tv_usec += 1000000;
|
|
|
9ae3a8 |
- t1.tv_sec--;
|
|
|
9ae3a8 |
- }
|
|
|
9ae3a8 |
- t1.tv_sec -= t2.tv_sec;
|
|
|
9ae3a8 |
- return t1;
|
|
|
9ae3a8 |
-}
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-double
|
|
|
9ae3a8 |
-tdiv(double value, struct timeval tv)
|
|
|
9ae3a8 |
-{
|
|
|
9ae3a8 |
- return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
|
|
|
9ae3a8 |
-}
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-#define HOURS(sec) ((sec) / (60 * 60))
|
|
|
9ae3a8 |
-#define MINUTES(sec) (((sec) % (60 * 60)) / 60)
|
|
|
9ae3a8 |
-#define SECONDS(sec) ((sec) % 60)
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-void
|
|
|
9ae3a8 |
-timestr(
|
|
|
9ae3a8 |
- struct timeval *tv,
|
|
|
9ae3a8 |
- char *ts,
|
|
|
9ae3a8 |
- size_t size,
|
|
|
9ae3a8 |
- int format)
|
|
|
9ae3a8 |
-{
|
|
|
9ae3a8 |
- double usec = (double)tv->tv_usec / 1000000.0;
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
- if (format & TERSE_FIXED_TIME) {
|
|
|
9ae3a8 |
- if (!HOURS(tv->tv_sec)) {
|
|
|
9ae3a8 |
- snprintf(ts, size, "%u:%02u.%02u",
|
|
|
9ae3a8 |
- (unsigned int) MINUTES(tv->tv_sec),
|
|
|
9ae3a8 |
- (unsigned int) SECONDS(tv->tv_sec),
|
|
|
9ae3a8 |
- (unsigned int) (usec * 100));
|
|
|
9ae3a8 |
- return;
|
|
|
9ae3a8 |
- }
|
|
|
9ae3a8 |
- format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
|
|
|
9ae3a8 |
- }
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
- if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
|
|
|
9ae3a8 |
- snprintf(ts, size, "%u:%02u:%02u.%02u",
|
|
|
9ae3a8 |
- (unsigned int) HOURS(tv->tv_sec),
|
|
|
9ae3a8 |
- (unsigned int) MINUTES(tv->tv_sec),
|
|
|
9ae3a8 |
- (unsigned int) SECONDS(tv->tv_sec),
|
|
|
9ae3a8 |
- (unsigned int) (usec * 100));
|
|
|
9ae3a8 |
- } else {
|
|
|
9ae3a8 |
- snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
|
|
|
9ae3a8 |
- }
|
|
|
9ae3a8 |
-}
|
|
|
9ae3a8 |
diff --git a/cmd.h b/cmd.h
|
|
|
9ae3a8 |
index da0c7cf..9907795 100644
|
|
|
9ae3a8 |
--- a/cmd.h
|
|
|
9ae3a8 |
+++ b/cmd.h
|
|
|
9ae3a8 |
@@ -43,20 +43,6 @@ void qemuio_add_command(const cmdinfo_t *ci);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
int qemuio_command_usage(const cmdinfo_t *ci);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
-/* from input.h */
|
|
|
9ae3a8 |
-void cvtstr(double value, char *str, size_t sz);
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-struct timeval tsub(struct timeval t1, struct timeval t2);
|
|
|
9ae3a8 |
-double tdiv(double value, struct timeval tv);
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-enum {
|
|
|
9ae3a8 |
- DEFAULT_TIME = 0x0,
|
|
|
9ae3a8 |
- TERSE_FIXED_TIME = 0x1,
|
|
|
9ae3a8 |
- VERBOSE_FIXED_TIME = 0x2
|
|
|
9ae3a8 |
-};
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
-void timestr(struct timeval *tv, char *str, size_t sz, int flags);
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
bool qemuio_command(const char *cmd);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
#endif /* __COMMAND_H__ */
|
|
|
9ae3a8 |
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
|
|
|
9ae3a8 |
index 27a903f..1db7fb9 100644
|
|
|
9ae3a8 |
--- a/qemu-io-cmds.c
|
|
|
9ae3a8 |
+++ b/qemu-io-cmds.c
|
|
|
9ae3a8 |
@@ -127,6 +127,110 @@ static int64_t cvtnum(const char *s)
|
|
|
9ae3a8 |
return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+#define EXABYTES(x) ((long long)(x) << 60)
|
|
|
9ae3a8 |
+#define PETABYTES(x) ((long long)(x) << 50)
|
|
|
9ae3a8 |
+#define TERABYTES(x) ((long long)(x) << 40)
|
|
|
9ae3a8 |
+#define GIGABYTES(x) ((long long)(x) << 30)
|
|
|
9ae3a8 |
+#define MEGABYTES(x) ((long long)(x) << 20)
|
|
|
9ae3a8 |
+#define KILOBYTES(x) ((long long)(x) << 10)
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+#define TO_EXABYTES(x) ((x) / EXABYTES(1))
|
|
|
9ae3a8 |
+#define TO_PETABYTES(x) ((x) / PETABYTES(1))
|
|
|
9ae3a8 |
+#define TO_TERABYTES(x) ((x) / TERABYTES(1))
|
|
|
9ae3a8 |
+#define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
|
|
|
9ae3a8 |
+#define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
|
|
|
9ae3a8 |
+#define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static void cvtstr(double value, char *str, size_t size)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ char *trim;
|
|
|
9ae3a8 |
+ const char *suffix;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (value >= EXABYTES(1)) {
|
|
|
9ae3a8 |
+ suffix = " EiB";
|
|
|
9ae3a8 |
+ snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
|
|
|
9ae3a8 |
+ } else if (value >= PETABYTES(1)) {
|
|
|
9ae3a8 |
+ suffix = " PiB";
|
|
|
9ae3a8 |
+ snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
|
|
|
9ae3a8 |
+ } else if (value >= TERABYTES(1)) {
|
|
|
9ae3a8 |
+ suffix = " TiB";
|
|
|
9ae3a8 |
+ snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
|
|
|
9ae3a8 |
+ } else if (value >= GIGABYTES(1)) {
|
|
|
9ae3a8 |
+ suffix = " GiB";
|
|
|
9ae3a8 |
+ snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
|
|
|
9ae3a8 |
+ } else if (value >= MEGABYTES(1)) {
|
|
|
9ae3a8 |
+ suffix = " MiB";
|
|
|
9ae3a8 |
+ snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
|
|
|
9ae3a8 |
+ } else if (value >= KILOBYTES(1)) {
|
|
|
9ae3a8 |
+ suffix = " KiB";
|
|
|
9ae3a8 |
+ snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ suffix = " bytes";
|
|
|
9ae3a8 |
+ snprintf(str, size - 6, "%f", value);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ trim = strstr(str, ".000");
|
|
|
9ae3a8 |
+ if (trim) {
|
|
|
9ae3a8 |
+ strcpy(trim, suffix);
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ strcat(str, suffix);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static struct timeval tsub(struct timeval t1, struct timeval t2)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ t1.tv_usec -= t2.tv_usec;
|
|
|
9ae3a8 |
+ if (t1.tv_usec < 0) {
|
|
|
9ae3a8 |
+ t1.tv_usec += 1000000;
|
|
|
9ae3a8 |
+ t1.tv_sec--;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ t1.tv_sec -= t2.tv_sec;
|
|
|
9ae3a8 |
+ return t1;
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static double tdiv(double value, struct timeval tv)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+#define HOURS(sec) ((sec) / (60 * 60))
|
|
|
9ae3a8 |
+#define MINUTES(sec) (((sec) % (60 * 60)) / 60)
|
|
|
9ae3a8 |
+#define SECONDS(sec) ((sec) % 60)
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+enum {
|
|
|
9ae3a8 |
+ DEFAULT_TIME = 0x0,
|
|
|
9ae3a8 |
+ TERSE_FIXED_TIME = 0x1,
|
|
|
9ae3a8 |
+ VERBOSE_FIXED_TIME = 0x2,
|
|
|
9ae3a8 |
+};
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static void timestr(struct timeval *tv, char *ts, size_t size, int format)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ double usec = (double)tv->tv_usec / 1000000.0;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (format & TERSE_FIXED_TIME) {
|
|
|
9ae3a8 |
+ if (!HOURS(tv->tv_sec)) {
|
|
|
9ae3a8 |
+ snprintf(ts, size, "%u:%02u.%02u",
|
|
|
9ae3a8 |
+ (unsigned int) MINUTES(tv->tv_sec),
|
|
|
9ae3a8 |
+ (unsigned int) SECONDS(tv->tv_sec),
|
|
|
9ae3a8 |
+ (unsigned int) (usec * 100));
|
|
|
9ae3a8 |
+ return;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
|
|
|
9ae3a8 |
+ snprintf(ts, size, "%u:%02u:%02u.%02u",
|
|
|
9ae3a8 |
+ (unsigned int) HOURS(tv->tv_sec),
|
|
|
9ae3a8 |
+ (unsigned int) MINUTES(tv->tv_sec),
|
|
|
9ae3a8 |
+ (unsigned int) SECONDS(tv->tv_sec),
|
|
|
9ae3a8 |
+ (unsigned int) (usec * 100));
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
/*
|
|
|
9ae3a8 |
* Parse the pattern argument to various sub-commands.
|
|
|
9ae3a8 |
*
|
|
|
9ae3a8 |
--
|
|
|
9ae3a8 |
1.8.3.1
|
|
|
9ae3a8 |
|