[PATCH V2 0/5] vm ticket in backend
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
V1 -> V2:
make ticket as sub-resource of a VM
A ticket is the credential to access VM.
Only who get the ticket can access a VM.
test this patch set:
set the ticket
$sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \
"Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \
-X PUT -d '{"passwd": "abcd"}'
get the ticket
$sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \
"Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/
ShaoHe Feng (5):
vm ticket in backend: update API.md
vm ticket in backend: update controller and API.json
vm ticket in backend: update model
vm ticket in backend: update mockmodel
vm ticket in backend: update test case
docs/API.md | 20 +++++++++++++++
src/kimchi/API.json | 14 ++++++++++
src/kimchi/control/vms.py | 13 ++++++++++
src/kimchi/i18n.py | 1 +
src/kimchi/mockmodel.py | 18 +++++++++++++
src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++
tests/test_model.py | 31 ++++++++++++++++++++++
tests/test_rest.py | 36 ++++++++++++++++++++++++++
8 files changed, 198 insertions(+)
--
1.9.3
10 years, 5 months
[PATCHv2 0/5] Create vm from image based template
by lvroyce@linux.vnet.ibm.com
From: Royce Lv <lvroyce(a)linux.vnet.ibm.com>
How to test:
create a image using:
POST /templates {'name':'mytemp', 'disks':[{'base':'a_base_img_path'}]}
create a vm using:
POST /vms {'template': '/templates/mytemp', 'pool'....}
Known issues:
1.This is only available for NFS and dir pool
2.template integrity is not checked, and base img is not protected.
3.Welcome ideas on how to test this feature.
Royce Lv (5):
Add image probe function
Change doc and api specification
Change 'cdrom' to a optional param
Integrate image os probe in vm template create
Create volume based on backing store image
docs/API.md | 3 ++-
docs/README.md | 9 ++++---
src/kimchi/API.json | 8 +++++-
src/kimchi/control/templates.py | 2 +-
src/kimchi/exception.py | 4 +++
src/kimchi/i18n.py | 8 +++++-
src/kimchi/imageinfo.py | 48 +++++++++++++++++++++++++++++++++
src/kimchi/mockmodel.py | 27 ++++++++++++++-----
src/kimchi/model/templates.py | 13 +++++----
src/kimchi/model/vms.py | 1 +
src/kimchi/utils.py | 16 +++++++++++
src/kimchi/vmtemplate.py | 60 +++++++++++++++++++++++++++--------------
tests/test_rest.py | 2 +-
13 files changed, 162 insertions(+), 39 deletions(-)
create mode 100644 src/kimchi/imageinfo.py
--
1.8.3.2
10 years, 5 months
[WIP] Filter VMs by users and groups
by Crístian Viana
This is a working version of the patchset. It will use the users and groups
metadata on each VM to decide if the current user is able to perform an
operation on the VM. If the user (1) has sudo access or (2) is listed in the VM
'users' metadata or (3) is part of at least one of the groups listed in the VM
'groups' metadata, they will be able to see and perform any operation on that VM.
The VMs listed by /vms are also filtered by the current user's permissions.
This patch contains the actual feature implementation. The tests and appropriate
updates to the mockmodel are not ready yet, as they happen to require more
changes in the current code than expected.
Crístian Viana (1):
Filter VMs by users and groups
src/kimchi/control/base.py | 4 +++
src/kimchi/model/vms.py | 63 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 65 insertions(+), 2 deletions(-)
--
1.9.3
10 years, 5 months
[PATCH] add a Base64 saftURL encode and decode function
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
These two functions are similar to the functions in
ui/js/novnc/base64.js
usage:
--- a/ui/pages/login.html.tmpl
+++ b/ui/pages/login.html.tmpl
@@ -36,6 +36,7 @@
<script src="$href('libs/jquery-ui.min.js')"></script>
<script src="$href('libs/jquery-ui-i18n.min.js')"></script>
<script src="$href('js/kimchi.min.js')"></script>
+<script src="$href('js/Base64saftURL.js')"></script>
<style type="text/css">
.topbar select {
float: right;
then in UI:
Base64.encode("f4>&^bc")
"ZjQ-Jl5iYw=="
Base64.decode("ZjQ-Jl5iYw==")
"f4>&^bc"
this is just a sample.
we can add it to ui/js/src/kimchi.utils.js
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
ui/js/Base64saftURL.js | 110 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+)
create mode 100644 ui/js/Base64saftURL.js
diff --git a/ui/js/Base64saftURL.js b/ui/js/Base64saftURL.js
new file mode 100644
index 0000000..8880a7e
--- /dev/null
+++ b/ui/js/Base64saftURL.js
@@ -0,0 +1,110 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtoo...
+
+/*jslint white: false, bitwise: false, plusplus: false */
+/*global console */
+
+var Base64 = {
+
+/* Convert data (an array of integers) to a Base64 string. */
+toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_='.split(''),
+base64Pad : '=',
+
+encode: function (data) {
+ "use strict";
+ var result = '';
+ var toBase64Table = Base64.toBase64Table;
+ var length = data.length
+ var lengthpad = (length%3);
+ var i = 0, j = 0;
+ // Convert every three bytes to 4 ascii characters.
+ /* BEGIN LOOP */
+ for (i = 0; i < (length - 2); i += 3) {
+ result += toBase64Table[data.charCodeAt(i) >> 2];
+ result += toBase64Table[((data.charCodeAt(i) & 0x03) << 4) + (data.charCodeAt(i+1) >> 4)];
+ result += toBase64Table[((data.charCodeAt(i+1) & 0x0f) << 2) + (data.charCodeAt(i+2) >> 6)];
+ result += toBase64Table[data.charCodeAt(i+2) & 0x3f];
+ }
+ /* END LOOP */
+
+ // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
+ if (lengthpad === 2) {
+ j = length - lengthpad;
+ result += toBase64Table[data.charCodeAt(j) >> 2];
+ result += toBase64Table[((data.charCodeAt(j) & 0x03) << 4) + (data.charCodeAt(j+1) >> 4)];
+ result += toBase64Table[(data.charCodeAt(j+1) & 0x0f) << 2];
+ result += toBase64Table[64];
+ } else if (lengthpad === 1) {
+ j = length - lengthpad;
+ result += toBase64Table[data.charCodeAt(j) >> 2];
+ result += toBase64Table[(data.charCodeAt(j) & 0x03) << 4];
+ result += toBase64Table[64];
+ result += toBase64Table[64];
+ }
+
+ return result;
+},
+
+/* Convert Base64 data to a string */
+toBinaryTable : [
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,62,-1,-1,
+ 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
+ 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,63,
+ -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+ 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+],
+
+decode: function (data, offset) {
+ "use strict";
+ offset = typeof(offset) !== 'undefined' ? offset : 0;
+ var toBinaryTable = Base64.toBinaryTable;
+ var base64Pad = Base64.base64Pad;
+ var result, result_length, idx, i, c, padding;
+ var leftbits = 0; // number of bits decoded, but yet to be appended
+ var leftdata = 0; // bits decoded, but yet to be appended
+
+ // Convert one by one.
+ /* BEGIN LOOP */
+ result = ""
+ for (idx = 0, i = offset; i < data.length; i++) {
+ c = toBinaryTable[data.charCodeAt(i) & 0x7f];
+ padding = (data.charAt(i) === base64Pad);
+ // Skip illegal characters and whitespace
+ if (c === -1) {
+ console.error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
+ continue;
+ }
+
+ // Collect data into leftdata, update bitcount
+ leftdata = (leftdata << 6) | c;
+ leftbits += 6;
+
+ // If we have 8 or more bits, append 8 bits to the result
+ if (leftbits >= 8) {
+ leftbits -= 8;
+ // Append if not padding.
+ if (!padding) {
+ idx++;
+ result += String.fromCharCode((leftdata >> leftbits) & 0xff);
+ }
+ leftdata &= (1 << leftbits) - 1;
+ }
+ }
+ /* END LOOP */
+
+ // If there are any bits left, the base64 string was corrupted
+ if (leftbits) {
+ throw {name: 'Base64-Error',
+ message: 'Corrupted base64 string'};
+ }
+
+ return result;
+}
+
+}; /* End of Base64 namespace */
--
1.9.3
10 years, 5 months
[PATCH 0/4] Let frontend redirect user after logging
by alinefm@linux.vnet.ibm.com
From: Aline Manera <alinefm(a)linux.vnet.ibm.com>
Aline Manera (4):
Update test case to reflect new login design
Remove former login design files
Remove special console rules from nginx configuration
Let frontend redirect user after logging
src/kimchi/auth.py | 10 +--
src/kimchi/root.py | 19 +----
src/nginx.conf.in | 11 ---
tests/test_rest.py | 2 +-
ui/css/theme-default/login-window.css | 90 ------------------------
ui/js/src/kimchi.login.js | 64 +++++++++++++++++
ui/js/src/kimchi.login_window.js | 128 ----------------------------------
ui/pages/login-window.html.tmpl | 53 --------------
ui/pages/login.html.tmpl | 36 ++--------
9 files changed, 72 insertions(+), 341 deletions(-)
delete mode 100644 ui/css/theme-default/login-window.css
create mode 100644 ui/js/src/kimchi.login.js
delete mode 100644 ui/js/src/kimchi.login_window.js
delete mode 100644 ui/pages/login-window.html.tmpl
--
1.9.3
10 years, 5 months
[PATCH 0/3 V2] authorization: Backend changes
by alinefm@linux.vnet.ibm.com
From: Aline Manera <alinefm(a)linux.vnet.ibm.com>
V1 -> V2:
- Add "access" elements to describe role/view for each tab
- Return a role map in /login
For each tab, a role will be returned. That way we have more flexibility to
change user role per tab
- Add "access" parameter to VM.lookup()
As the user will have full access to the VM assigned to it, return
"access=full" for all them
Aline Manera (3):
authorization: Update /login to return user roles instead of sudo
parameter
authorization: Add "access" elements to tabs.xml to describe user view
authorization: Add "access" parameter to VM resource
config/ui/tabs.xml | 15 +++++++++++++++
plugins/sample/ui/config/tab-ext.xml | 3 +++
src/kimchi/auth.py | 19 ++++++++++++++-----
src/kimchi/mockmodel.py | 3 ++-
src/kimchi/model/vms.py | 3 ++-
src/kimchi/utils.py | 15 +++++++++++++++
tests/test_rest.py | 6 ++++++
tests/utils.py | 6 +++---
8 files changed, 60 insertions(+), 10 deletions(-)
--
1.9.3
10 years, 5 months
[RFC] filter the users of host system
by Sheldon
Now kimchi uses host system users to login.
In fedora most of system users are not allowed to login. so we should
filter them.
but in ubuntu, it seems most system user still can login. but their
pw_shell are /bin/sh it is softlink to */bin/bash
*
Now I'd like to just list the users who's pw_shell are /bin/bash
Not sure all distribution can works well by this way.
I have just checked fedora and ubuntu, seems it can works.
so any one can help check if any exception on your distribution?
*root:x:0:0:root:/root:/bin/bash*
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL
Stack:/var/lib/avahi-autoipd:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:999:User for polkitd:/:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
colord:x:998:998:User for colord:/var/lib/colord:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
geoclue:x:997:996:User for geoclue:/var/lib/geoclue:/sbin/nologin
chrony:x:996:995::/var/lib/chrony:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd
daemon:/dev/null:/sbin/nologin
unbound:x:995:994:Unbound DNS resolver:/etc/unbound:/sbin/nologin
openvpn:x:994:993:OpenVPN:/etc/openvpn:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
pulse:x:993:991:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:992:989::/run/gnome-initial-setup/:/sbin/nologin
nm-openconnect:x:991:988:NetworkManager user for OpenConnect:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
*shhfeng:x:1000:1000:shhfeng:/home/shhfeng:/bin/bash*
qemu:x:107:107:qemu user:/:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
saslauth:x:990:76:"Saslauthd user":/run/saslauthd:/sbin/nologin
*guest:x:1001:1001::/home/guest:/bin/bash*
nginx:x:989:984:Nginx web server:/var/lib/nginx:/sbin/nologin
but in ubuntu, it seems most system user still can login. but their
pw_shell are /bin/sh it is softlink to */bin/bash*
*root:x:0:0:root:/root:/bin/bash*
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
syslog:x:101:103::/home/syslog:/bin/false
messagebus:x:102:105::/var/run/dbus:/bin/false
usbmux:x:103:46:usbmux daemon,,,:/home/usbmux:/bin/false
dnsmasq:x:104:65534:dnsmasq,,,:/var/lib/misc:/bin/false
avahi-autoipd:x:105:111:Avahi autoip
daemon,,,:/var/lib/avahi-autoipd:/bin/false
kernoops:x:106:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false
rtkit:x:107:113:RealtimeKit,,,:/proc:/bin/false
whoopsie:x:108:114::/nonexistent:/bin/false
speech-dispatcher:x:109:29:Speech
Dispatcher,,,:/var/run/speech-dispatcher:/bin/sh
avahi:x:110:116:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
lightdm:x:111:117:Light Display Manager:/var/lib/lightdm:/bin/false
pulse:x:112:119:PulseAudio daemon,,,:/var/run/pulse:/bin/false
hplip:x:113:7:HPLIP system user,,,:/var/run/hplip:/bin/false
colord:x:114:122:colord colour management
daemon,,,:/var/lib/colord:/bin/false
saned:x:115:123::/home/saned:/bin/false
*royce:x:1000:1000:royce,,,:/home/royce:/bin/bash*
libvirt-qemu:x:116:126:Libvirt Qemu,,,:/var/lib/libvirt:/bin/false
libvirt-dnsmasq:x:117:125:Libvirt
Dnsmasq,,,:/var/lib/libvirt/dnsmasq:/bin/false
statd:x:118:65534::/var/lib/nfs:/bin/false
sshd:x:119:65534::/var/run/sshd:/usr/sbin/nologi
--
Thanks and best regards!
Sheldon Feng(???)<shaohef(a)linux.vnet.ibm.com>
IBM Linux Technology Center
10 years, 5 months
[PATCH v5 00/10] Debug Report Rename Feature
by Hongliang Wang
Enable debug report rename feature in this patch set.
Please apply the following patch set first:
* [PATCH 0/2] Bug Fixes: Mock Model with Debug Report Generate
v4 -> v5:
5a) Implemented mock model
(Aline's comment)
5b) Implemented test code
(Aline's comment)
v3 -> v4:
4a) Updated according to dependency changes
v2 -> v3:
3a) Added check for name existence when renaming a report
(Yu Xin's comment)
v1 -> v2:
2a) Retrieved the Right Generated Time for Debug Report
(Wen Wang's comment)
2b) Sorted debug reports by Generated Time Descendingly
(Wen Wang's comment)
2c) Enabled Form Fields after Request Processed
(Yuxin's comment)
Hongliang Wang (9):
Debug Report Rename: Update API.json
Debug Report Rename: Update API.md
Debug Report Rename: Implement Back-end
Debug Report: Use Generated Time instead of Most Changed Time
Debug Report: Sort Reports by Generated Time Descendingly
Debug Report Rename UI: Add API in kimchi.api.js
Debug Report Rename UI: Add Rename Page
Debug Report Rename UI: Enable Rename in Host Tab
Debug Report: Update MockModel
Royce Lv (1):
Debug Report Rename: Update Test Code
docs/API.md | 3 ++
src/kimchi/API.json | 11 +++++++
src/kimchi/control/debugreports.py | 8 ++++-
src/kimchi/mockmodel.py | 18 +++++++++++-
src/kimchi/model/debugreports.py | 18 +++++++++++-
tests/test_model.py | 7 ++++-
tests/test_rest.py | 6 +++-
ui/css/theme-default/report-rename.css | 22 ++++++++++++++
ui/js/src/kimchi.api.js | 12 ++++++++
ui/js/src/kimchi.host.js | 35 +++++++++++++++-------
ui/js/src/kimchi.report_rename_main.js | 41 ++++++++++++++++++++++++++
ui/pages/report-rename.html.tmpl | 53 ++++++++++++++++++++++++++++++++++
12 files changed, 218 insertions(+), 16 deletions(-)
create mode 100644 ui/css/theme-default/report-rename.css
create mode 100644 ui/js/src/kimchi.report_rename_main.js
create mode 100644 ui/pages/report-rename.html.tmpl
--
1.8.1.4
10 years, 5 months
[PATCH v6 00/10] Debug Report Rename Feature
by Hongliang Wang
Enable debug report rename feature in this patch set.
Please apply the following patch set first:
* [PATCH 0/2] Bug Fixes: Mock Model with Debug Report Generate
v5 -> v6:
6a) Updated regexp of report name in API.json
(Aline's comment)
6b) Updated license statement
(Aline's comment)
v4 -> v5:
5a) Implemented mock model
(Aline's comment)
5b) Implemented test code
(Aline's comment)
v3 -> v4:
4a) Updated according to dependency changes
v2 -> v3:
3a) Added check for name existence when renaming a report
(Yu Xin's comment)
v1 -> v2:
2a) Retrieved the Right Generated Time for Debug Report
(Wen Wang's comment)
2b) Sorted debug reports by Generated Time Descendingly
(Wen Wang's comment)
2c) Enabled Form Fields after Request Processed
(Yuxin's comment)
Hongliang Wang (9):
Debug Report Rename: Update API.json
Debug Report Rename: Update API.md
Debug Report Rename: Implement Back-end
Debug Report: Use Generated Time instead of Most Changed Time
Debug Report: Sort Reports by Generated Time Descendingly
Debug Report Rename UI: Add API in kimchi.api.js
Debug Report Rename UI: Add Rename Page
Debug Report Rename UI: Enable Rename in Host Tab
Debug Report: Update MockModel
Royce Lv (1):
Debug Report Rename: Update Test Code
docs/API.md | 3 ++
src/kimchi/API.json | 11 +++++++
src/kimchi/control/debugreports.py | 8 ++++-
src/kimchi/mockmodel.py | 18 ++++++++++-
src/kimchi/model/debugreports.py | 18 ++++++++++-
tests/test_model.py | 7 +++-
tests/test_rest.py | 6 +++-
ui/css/theme-default/report-rename.css | 39 +++++++++++++++++++++++
ui/js/src/kimchi.api.js | 12 +++++++
ui/js/src/kimchi.host.js | 35 +++++++++++++-------
ui/js/src/kimchi.report_rename_main.js | 58 ++++++++++++++++++++++++++++++++++
ui/pages/report-rename.html.tmpl | 53 +++++++++++++++++++++++++++++++
12 files changed, 252 insertions(+), 16 deletions(-)
create mode 100644 ui/css/theme-default/report-rename.css
create mode 100644 ui/js/src/kimchi.report_rename_main.js
create mode 100644 ui/pages/report-rename.html.tmpl
--
1.8.1.4
10 years, 5 months
[PATCH 0/2] Bug Fixes: Mock Model with Debug Report Generate
by Hongliang Wang
Fixed 2 bugs:
1). When in mock model, generate report doesn't work if report name is left as
blank.
2). When in mock model, generate report window will never disappear even after
the report is generated.
Hongliang Wang (2):
MockModel: Can't Generate Report if Name is not Given
Debug Report UI: Generate Report Doesn't Work with Mock Model
src/kimchi/mockmodel.py | 8 +++++++-
ui/js/src/kimchi.report_add_main.js | 39 ++++++++++++++++++++-----------------
2 files changed, 28 insertions(+), 19 deletions(-)
--
1.8.1.4
10 years, 5 months